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, leaftitle[n]/d[0,10,32]
601 // (with fixed_array that can be a multi-dimensional array).
602 TString sname = leaf->GetTitle();
603 auto slash = sname.First("/");
604 sname = (slash == TString::kNPOS) ? sname : sname(0, slash);
605 const char *tname = sname.Data();
606 char *leaf_dim = (char*)strstr( tname, "[" );
607
608 const char *bname = leaf->GetBranch()->GetName();
609 char *branch_dim = (char*)strstr(bname,"[");
610 if (branch_dim) branch_dim++; // skip the '['
611
612 bool isString = false;
613 if (leaf->IsA() == TLeafElement::Class()) {
614 Int_t type =((TBranchElement*)leaf->GetBranch())->GetStreamerType();
617 } else {
618 isString = (leaf->IsA() == TLeafC::Class());
619 }
620 if (leaf_dim) {
621 leaf_dim++; // skip the '['
623 // then both are NOT the same so do the leaf title first:
627 && (leaf_dim+strlen(branch_dim))[0]=='[') {
628 // we have extra info in the leaf title
630 }
631 }
632 if (branch_dim) {
633 // then both are NOT same so do the branch name next:
634 if (isString) {
636 } else {
638 }
639 }
640 if (leaf->IsA() == TLeafElement::Class()) {
641 TBranchElement* branch = (TBranchElement*) leaf->GetBranch();
642 if (branch->GetBranchCount2()) {
643
644 if (!branch->GetBranchCount()) {
645 Warning("DefinedVariable",
646 "Noticed an incorrect in-memory TBranchElement object (%s).\nIt has a BranchCount2 but no BranchCount!\nThe result might be incorrect!",
647 branch->GetName());
648 return numberOfVarDim;
649 }
650
651 // Switch from old direct style to using a TLeafInfo
652 if (fLookupType[code] == kDataMember)
653 Warning("DefinedVariable",
654 "Already in kDataMember mode when handling multiple variable dimensions");
655 fLookupType[code] = kDataMember;
656
657 // Feed the information into the Dimensions system
659
660 }
661 }
662 return numberOfVarDim;
663}
664
665////////////////////////////////////////////////////////////////////////////////
666/// This method check for treat the case where expression contains `Alt$(`
667/// and load up both fAliases and fExpr. It also checks for `MinIf$(` and `MaxIf$(`
668/// We return:
669/// - -1 in case of failure
670/// - 0 in case we did not find any of `Alt$(`, `MinIf$(`, or `MaxIf$(`
671/// - the action number in case of success. (kAlternate, kMinIf or kMaxIf)
672
674{
675 static const char *altfunc = "Alt$(";
676 static const char *minfunc = "MinIf$(";
677 static const char *maxfunc = "MaxIf$(";
678 Int_t action = 0;
679 Int_t start = 0;
680
681 if ( strncmp(expression,altfunc,strlen(altfunc))==0
682 && expression[strlen(expression)-1]==')' ) {
684 start = strlen(altfunc);
685 }
686 if ( strncmp(expression,maxfunc,strlen(maxfunc))==0
687 && expression[strlen(expression)-1]==')' ) {
688 action = kMaxIf;
689 start = strlen(maxfunc);
690 }
691 if ( strncmp(expression,minfunc,strlen(minfunc))==0
692 && expression[strlen(expression)-1]==')' ) {
693 action = kMinIf;
694 start = strlen(minfunc);
695 }
696
697 if (action) {
698 TString full = expression;
701 int paran = 0;
702 int instr = 0;
703 int brack = 0;
704 for(unsigned int i=start;i<strlen(expression);++i) {
705 switch (expression[i]) {
706 case '(': paran++; break;
707 case ')': paran--; break;
708 case '"': instr = instr ? 0 : 1; break;
709 case '[': brack++; break;
710 case ']': brack--; break;
711 };
712 if (expression[i]==',' && paran==0 && instr==0 && brack==0) {
713 part1 = full( start, i-start );
714 part2 = full( i+1, full.Length() -1 - (i+1) );
715 break; // out of the for loop
716 }
717 }
718 if (part1.Length() && part2.Length()) {
719 TTreeFormula *primary = new TTreeFormula("primary",part1,fTree);
720 TTreeFormula *alternate = new TTreeFormula("alternate",part2,fTree);
721
722 short isstring = 0;
723
724 if (action == kAlternate) {
725 if (alternate->GetManager()->GetMultiplicity() != 0 ) {
726 Error("DefinedVariable","The 2nd arguments in %s can not be an array (%s,%d)!",
727 expression,alternate->GetTitle(),
728 alternate->GetManager()->GetMultiplicity());
729 return -1;
730 }
731
732 // Should check whether we have strings.
733 if (primary->IsString()) {
734 if (!alternate->IsString()) {
735 Error("DefinedVariable",
736 "The 2nd arguments in %s has to return the same type as the 1st argument (string)!",
737 expression);
738 return -1;
739 }
740 isstring = 1;
741 } else if (alternate->IsString()) {
742 Error("DefinedVariable",
743 "The 2nd arguments in %s has to return the same type as the 1st argument (numerical type)!",
744 expression);
745 return -1;
746 }
747 } else {
748 primary->GetManager()->Add( alternate );
749 primary->GetManager()->Sync();
750 if (primary->IsString() || alternate->IsString()) {
751 if (!alternate->IsString()) {
752 Error("DefinedVariable",
753 "The arguments of %s can not be strings!",
754 expression);
755 return -1;
756 }
757 }
758 }
759
761 fExpr[fNoper] = "";
763 ++fNoper;
764
766 return (Int_t)kAlias + isstring;
767 }
768 }
769 return 0;
770}
771
772////////////////////////////////////////////////////////////////////////////////
773/// Decompose 'expression' as pointing to something inside the leaf
774/// Returns:
775/// - -2 Error: some information is missing (message already printed)
776/// - -1 Error: Syntax is incorrect (message already printed)
777/// - 0
778/// - >0 the value returns is the action code.
779
781{
782 Int_t action = 0;
783
785 char *current;
786
787 char scratch[kMaxLen]; scratch[0] = '\0';
788 char work[kMaxLen]; work[0] = '\0';
789
790 const char *right = subExpression;
792
793 TBranch *branch = leaf ? leaf->GetBranch() : nullptr;
794 Long64_t readentry = fTree->GetTree()->GetReadEntry();
795 if (readentry < 0) readentry=0;
796
797 bool useLeafReferenceObject = false;
798 Int_t code = fNcodes-1;
799
800 // Make a check to prevent problem with some corrupted files (missing TStreamerInfo).
801 if (leaf && leaf->IsA()==TLeafElement::Class()) {
802 TBranchElement *br = nullptr;
803 if( branch->IsA() == TBranchElement::Class() )
804 {
806
807 if ( br->GetInfo() == nullptr ) {
808 Error("DefinedVariable","Missing StreamerInfo for %s. We will be unable to read!",
809 name.Data());
810 return -2;
811 }
812 }
813
814 TBranch *bmom = branch->GetMother();
815 if( bmom->IsA() == TBranchElement::Class() )
816 {
817 TBranchElement *mom = (TBranchElement*)br->GetMother();
818 if (mom!=br) {
819 if (mom->GetInfo()==nullptr) {
820 Error("DefinedVariable","Missing StreamerInfo for %s."
821 " We will be unable to read!",
822 mom->GetName());
823 return -2;
824 }
825 if ((mom->GetType()) < -1 && !mom->GetAddress()) {
826 Error("DefinedVariable", "Address not set when the type of the branch is negative for for %s. We will be unable to read!", mom->GetName());
827 return -2;
828 }
829 }
830 }
831 }
832
833 // We need to record the location in the list of leaves because
834 // the tree might actually be a chain and in that case the leaf will
835 // change from tree to tree!.
836
837 // Let's reconstruct the name of the leaf, including the possible friend alias
839 const char* alias = nullptr;
840 if (leaf) {
841 if (realtree) alias = realtree->GetFriendAlias(leaf->GetBranch()->GetTree());
842 if (!alias && realtree!=fTree) {
843 // Let's try on the chain
844 alias = fTree->GetFriendAlias(leaf->GetBranch()->GetTree());
845 }
846 }
848 if (alias) {
849 leafname_len = strlen(alias) + strlen(leaf->GetName()) + 1;
850 snprintf(scratch,kMaxLen-1,"%s.%s",alias,leaf->GetName()); // does not null-terminate if truncation happens
851 }
852 else if (leaf) {
853 leafname_len = strlen(leaf->GetName());
854 strlcpy(scratch,leaf->GetName(),kMaxLen); // null-terminates if truncation happens
855 }
856 if (leafname_len > kMaxLen - 1) {
857 Error("TTreeFormula",
858 "Length of leafname (%d) exceeds maximum allowed by the buffer (%d), formula will be truncated.",
859 leafname_len, kMaxLen - 1);
860 return -1;
861 }
862
863
865 if (leaf) {
866 tleaf = leaf->GetBranch()->GetTree();
867 fCodes[code] = tleaf->GetListOfLeaves()->IndexOf(leaf);
868 const char *mother_name = leaf->GetBranch()->GetMother()->GetName();
869 TString br_extended_name; // Could do ( strlen(mother_name)+strlen( leaf->GetBranch()->GetName() ) + 2 )
870 if (leaf->GetBranch()!=leaf->GetBranch()->GetMother()) {
871 if (mother_name[strlen(mother_name)-1]!='.') {
873 br_extended_name.Append('.');
874 }
875 }
876 br_extended_name.Append( leaf->GetBranch()->GetName() );
877 Ssiz_t dim = br_extended_name.First('[');
878 if (dim >= 0) br_extended_name.Remove(dim);
879
883 }
884
885 // If the leaf belongs to a friend tree which has an index, we might
886 // be in the case where some entry do not exist.
887 if (tleaf != realtree && tleaf->GetTreeIndex()) {
888 // reset the multiplicity
889 if (fMultiplicity >= 0) fMultiplicity = 1;
890 }
891
892 // Analyze the content of 'right'
893
894 // Try to find out the class (if any) of the object in the leaf.
895 TClass * cl = nullptr;
896 TFormLeafInfo *maininfo = nullptr;
897 TFormLeafInfo *previnfo = nullptr;
898 bool unwindCollection = false;
899 const static TClassRef stdStringClass = TClass::GetClass("string");
900
901 if (leaf==nullptr) {
902 TNamed *names = (TNamed*)fLeafNames.UncheckedAt(code);
903 fLeafNames.AddAt(nullptr,code);
905 fLeaves.AddAt(nullptr,code);
906
907 cl = what ? what->IsA() : TTree::Class();
910
911 delete names;
912 } else if (leaf->InheritsFrom(TLeafObject::Class()) ) {
913 TBranchObject *bobj = (TBranchObject*)leaf->GetBranch();
914 cl = TClass::GetClass(bobj->GetClassName());
915 } else if (leaf->InheritsFrom(TLeafElement::Class())) {
916 TBranchElement *branchEl = (TBranchElement *)leaf->GetBranch();
917 branchEl->SetupAddresses();
918 TStreamerInfo *info = branchEl->GetInfo();
919 TStreamerElement *element = nullptr;
920 Int_t type = branchEl->GetStreamerType();
921 switch(type) {
934 element = info->GetElement(branchEl->GetID());
935 if (element) cl = element->GetClassPointer();
936 }
937 break;
946 element = info->GetElement(branchEl->GetID());
947 if (element){
948 cl = element->GetClassPointer();
949 }
950 }
951 break;
952 case -1: {
953 cl = info->GetClass();
954 }
955 break;
956 }
957
958 // If we got a class object, we need to verify whether it is on a
959 // split TClonesArray sub branch.
960 if (cl && branchEl->GetBranchCount()) {
961 if (branchEl->GetType()==31) {
962 // This is inside a TClonesArray.
963
964 if (!element) {
965 Warning("DefinedVariable",
966 "Missing TStreamerElement in object in TClonesArray section");
967 return -2;
968 }
970
971 // The following code was commented out because in THIS case
972 // the dimension are actually handled by parsing the title and name of the leaf
973 // and branch (see a little further)
974 // The dimension needs to be handled!
975 // numberOfVarDim += RegisterDimensions(code,clonesinfo);
976
978
979 // We skip some cases because we can assume we have an object.
980 Int_t offset=0;
981 info->GetStreamerElement(element->GetName(),offset);
992 previnfo = new TFormLeafInfoPointer(cl,offset+branchEl->GetOffset(),element);
993 } else {
994 previnfo = new TFormLeafInfo(cl,offset+branchEl->GetOffset(),element);
995 }
996 maininfo->fNext = previnfo;
997 unwindCollection = true;
998
999 } else if (branchEl->GetType()==41) {
1000
1001 // This is inside a Collection
1002
1003 if (!element) {
1004 Warning("DefinedVariable","Missing TStreamerElement in object in Collection section");
1005 return -2;
1006 }
1007 // First we need to recover the collection.
1008 TBranchElement *count = branchEl->GetBranchCount();
1010 if ( count->GetID() >= 0 ) {
1012 count->GetInfo()->GetElement(count->GetID());
1013 TClass *collectionCl = collectionElement->GetClassPointer();
1014
1017 } else {
1021 }
1022
1023 // The following code was commented out because in THIS case
1024 // the dimension are actually handled by parsing the title and name of the leaf
1025 // and branch (see a little further)
1026 // The dimension needs to be handled!
1027 // numberOfVarDim += RegisterDimensions(code,clonesinfo);
1028
1030
1031 // We skip some cases because we can assume we have an object.
1032 Int_t offset=0;
1033 info->GetStreamerElement(element->GetName(),offset);
1044 previnfo = new TFormLeafInfoPointer(cl,offset+branchEl->GetOffset(),element);
1045 } else {
1046 previnfo = new TFormLeafInfo(cl,offset+branchEl->GetOffset(),element);
1047 }
1048 maininfo->fNext = previnfo;
1049 unwindCollection = true;
1050 }
1051 } else if ( branchEl->GetType()==3) {
1055 } else {
1056 clonesinfo = new TFormLeafInfoClones(cl, 0, true);
1057 // The dimension needs to be handled!
1059
1060 }
1063
1064 } else if (!useLeafCollectionObject && branchEl->GetType()==4) {
1065
1069 } else {
1070 collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, true);
1071 // The dimension needs to be handled!
1073 }
1074
1077
1078 } else if (branchEl->GetStreamerType()==-1 && cl && cl->GetCollectionProxy()) {
1079
1081
1085
1086 } else {
1088 // The dimension needs to be handled!
1090
1093
1094 if (cl->GetCollectionProxy()->GetValueClass()!=nullptr &&
1095 cl->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()!=nullptr) {
1096
1099
1100 fHasMultipleVarDim[code] = true;
1102 previnfo->fNext = multi;
1103 cl = cl->GetCollectionProxy()->GetValueClass();
1104 multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false);
1105 previnfo = multi->fNext;
1106
1107 }
1108 if (cl->GetCollectionProxy()->GetValueClass()==nullptr &&
1109 cl->GetCollectionProxy()->GetType()>0) {
1110
1111 previnfo->fNext =
1113 previnfo = previnfo->fNext;
1114 } else {
1115 // nothing to do
1116 }
1117 }
1118
1119 } else if (strlen(right)==0 && cl && element && final) {
1120
1121 TClass *elemCl = element->GetClassPointer();
1123 && elemCl && elemCl->GetCollectionProxy()
1124 && elemCl->GetCollectionProxy()->GetValueClass()
1125 && elemCl->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()) {
1126
1128 new TFormLeafInfoCollection(cl, 0, elemCl);
1129
1130 // The dimension needs to be handled!
1132
1135
1138 elemCl->GetCollectionProxy()->GetValueClass(),
1140
1141 fHasMultipleVarDim[code] = true;
1143 previnfo->fNext = multi;
1144 cl = elemCl->GetCollectionProxy()->GetValueClass();
1145 multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false);
1146 previnfo = multi->fNext;
1147
1148 if (cl->GetCollectionProxy()->GetValueClass()==nullptr &&
1149 cl->GetCollectionProxy()->GetType()>0) {
1150
1151 previnfo->fNext =
1153 previnfo = previnfo->fNext;
1154 }
1155
1156 } else if (!useLeafCollectionObject
1157 && elemCl && elemCl->GetCollectionProxy()
1158 && elemCl->GetCollectionProxy()->GetValueClass()==nullptr
1159 && elemCl->GetCollectionProxy()->GetType()>0) {
1160
1161 // At this point we have an element which is inside a class (which is not
1162 // a collection) and this element of a collection of numerical type.
1163 // (Note: it is not possible to have more than one variable dimension
1164 // unless we were supporting variable size C-style array of collection).
1165
1167 new TFormLeafInfoCollection(cl, 0, elemCl);
1168
1169 // The dimension needs to be handled!
1171
1172 collectioninfo->fNext =
1173 new TFormLeafInfoNumerical(elemCl->GetCollectionProxy());
1174
1176 previnfo = maininfo->fNext;
1177
1178 } else if (!useLeafCollectionObject
1179 && elemCl && elemCl->GetCollectionProxy()) {
1180 if (elemCl->GetCollectionProxy()->GetValueClass()==TString::Class()) {
1181 right = "Data()";
1182 } else if (elemCl->GetCollectionProxy()->GetValueClass()==stdStringClass) {
1183 right = "c_str()";
1184 }
1185
1186 } else if (!element->IsaPointer()) {
1187
1190
1191 }
1192 }
1193 else if ( cl && cl->GetReferenceProxy() ) {
1194 if ( useLeafCollectionObject || fullExpression[0] == '@' || fullExpression[strlen(scratch)] == '@' ) {
1196 }
1197 else {
1198 if ( !maininfo ) {
1201 }
1203 for(Long64_t i=0; i<leaf->GetBranch()->GetEntries()-readentry; ++i) {
1204 R__LoadBranch(leaf->GetBranch(), readentry+i, fQuickLoad);
1205 void *refobj = maininfo->GetValuePointer(leaf,0);
1206 if (refobj) {
1207 cl = refproxy->GetValueClass(refobj);
1208 }
1209 if ( cl ) break;
1210 }
1211 if ( !cl ) {
1212 Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1213 return -1;
1214 }
1215 }
1216 }
1217 } else {
1218 // Regular/old TLeaf, there should not be anything afterward ...
1219 if (subExpression && subExpression[0]) {
1220 Error("ParseWithLeaf", "Found a numerical leaf but the name has trailing characters: \"%s\"", subExpression);
1221 return -1;
1222 }
1223 }
1224
1225 // Treat the dimension information in the leaf name, title and 2nd branch count
1227
1228 if (cl) {
1229 if (unwindCollection) {
1230 // So far we should get here only if we encounter a split collection of a class that contains
1231 // directly a collection.
1233
1234 if (!useLeafCollectionObject && cl && cl->GetCollectionProxy()) {
1237 fHasMultipleVarDim[code] = true;
1239 previnfo->fNext = multi;
1240
1241 multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false);
1242 previnfo = multi->fNext;
1243
1244 if (cl->GetCollectionProxy()->GetValueClass()==nullptr &&
1245 cl->GetCollectionProxy()->GetType()>0) {
1246
1247 previnfo->fNext =
1249 previnfo = previnfo->fNext;
1250 }
1251 } else if (!useLeafCollectionObject && cl == TClonesArray::Class()) {
1252
1255 fHasMultipleVarDim[code] = true;
1257 previnfo->fNext = multi;
1258
1259 multi->fNext = new TFormLeafInfoClones(cl, 0, false);
1260 previnfo = multi->fNext;
1261 }
1262 }
1263 Int_t offset=0;
1264 if (cl == TString::Class() && strcmp(right,"fData")==0) {
1265 // For backward compatibility replace TString::fData which no longer exist
1266 // by a call to TString::Data()
1267 right = "Data()";
1268 }
1269 Int_t nchname = strlen(right);
1270 TFormLeafInfo *leafinfo = nullptr;
1271 TStreamerElement* element = nullptr;
1272
1273 // Let see if the leaf was attempted to be casted.
1274 // Since there would have been something like
1275 // ((cast_class*)leafname)->.... we need to use
1276 // paran_level+1
1277 // Also we disable this functionality in case of TClonesArray
1278 // because it is not yet allowed to have 'inheritance' (or virtuality)
1279 // in play in a TClonesArray.
1280 {
1282 if (casted && cl != TClonesArray::Class()) {
1283 if ( ! casted->InheritsFrom(cl) ) {
1284 Error("DefinedVariable","%s does not inherit from %s. Casting not possible!",
1285 casted->GetName(),cl->GetName());
1286 return -2;
1287 }
1289 fHasCast = true;
1290 if (maininfo==nullptr) {
1292 }
1293 if (previnfo==nullptr) {
1295 } else {
1296 previnfo->fNext = leafinfo;
1298 }
1299 leafinfo = nullptr;
1300
1301 cl = casted;
1302 castqueue.AddAt(nullptr,paran_level);
1303 }
1304 }
1305 Int_t i;
1310 for (i=0, current = &(work[0]); i<=nchname;i++ ) {
1311 // We will treated the terminator as a token.
1312 if (right[i] == '(') {
1313 // Right now we do not allow nested parenthesis
1314 do {
1315 *current++ = right[i++];
1316 } while(right[i]!=')' && right[i]);
1317 *current++ = right[i];
1318 *current='\0';
1319 char *params = strchr(work,'(');
1320 if (params) {
1321 *params = 0; params++;
1322 } else params = (char *) ")";
1323 if (cl==nullptr) {
1324 Error("DefinedVariable","Can not call '%s' with a class",work);
1325 return -1;
1326 }
1327 if (!cl->HasDataMemberInfo() && !cl->GetCollectionProxy()) {
1328 Error("DefinedVariable","Class probably unavailable:%s",cl->GetName());
1329 return -2;
1330 }
1331 if (!useCollectionObject && cl == TClonesArray::Class()) {
1332 // We are not interested in the ClonesArray object but only
1333 // in its contents.
1334 // We need to retrieve the class of its content.
1335
1336 TBranch *clbranch = leaf->GetBranch();
1339 if (previnfo) clones = (TClonesArray*)previnfo->GetLocalValuePointer(leaf,0);
1340 else {
1341 bool top = (clbranch==((TBranchElement*)clbranch)->GetMother()
1342 || !leaf->IsOnTerminalBranch());
1344 if (leaf->IsA()==TLeafObject::Class()) {
1345 // in this case mother_cl is not really used
1346 mother_cl = cl;
1347 } else {
1348 mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1349 }
1351
1352 // The dimension needs to be handled!
1354
1357
1358 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1359 }
1360 TClass * inside_cl = clones ? clones->GetClass() : nullptr;
1361 cl = inside_cl;
1362
1363 }
1364 else if (!useCollectionObject && cl && cl->GetCollectionProxy() ) {
1365
1366 // We are NEVER (for now!) interested in the ClonesArray object but only
1367 // in its contents.
1368 // We need to retrieve the class of its content.
1369
1370 if (previnfo==nullptr) {
1371
1372 bool top = (branch==((TBranchElement*)branch)->GetMother()
1373 || !leaf->IsOnTerminalBranch());
1374
1376 if (leaf->IsA()==TLeafObject::Class()) {
1377 // in this case mother_cl is not really used
1378 mother_cl = cl;
1379 } else {
1380 mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
1381 }
1382
1384 new TFormLeafInfoCollection(mother_cl, 0,cl,top);
1385 // The dimension needs to be handled!
1387
1390
1391 }
1392
1394 if (inside_cl) cl = inside_cl;
1395 else if (cl->GetCollectionProxy()->GetType()>0) {
1396 Warning("DefinedVariable","Can not call method on content of %s in %s\n",
1397 cl->GetName(),name.Data());
1398 return -2;
1399 }
1400 }
1401 TMethodCall *method = nullptr;
1402 if (cl==nullptr) {
1403 Error("DefinedVariable",
1404 "Could not discover the TClass corresponding to (%s)!",
1405 right);
1406 return -2;
1407 } else if (cl==TClonesArray::Class() && strcmp(work,"size")==0) {
1408 method = new TMethodCall(cl, "GetEntriesFast", "");
1409 } else if (cl->GetCollectionProxy() && strcmp(work,"size")==0) {
1410 if (maininfo==nullptr) {
1413
1414 bool top = (branch==((TBranchElement*)branch)->GetMother()
1415 || !leaf->IsOnTerminalBranch());
1417 }
1419 }
1421 cl = nullptr;
1422 } else {
1423 if (!cl->HasDataMemberInfo()) {
1424 Error("DefinedVariable",
1425 "Can not call method %s on class without dictionary (%s)!",
1426 right,cl->GetName());
1427 return -2;
1428 }
1429 method = new TMethodCall(cl, work, params);
1430 }
1431 if (method) {
1432 if (!method->GetMethod()) {
1433 Error("DefinedVariable","Unknown method:%s in %s",right,cl->GetName());
1434 return -1;
1435 }
1436 switch(method->ReturnType()) {
1437 case TMethodCall::kLong:
1439 cl = nullptr;
1440 break;
1443 cl = nullptr;
1444 break;
1447 // 1 will be replaced by -1 when we know how to use strlen
1448 numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0
1449 cl = nullptr;
1450 break;
1452 {
1455 }
1456 break;
1457 default:
1458 Error("DefineVariable","Method %s from %s has an impossible return type %d",
1459 work,cl->GetName(), (Int_t)method->ReturnType());
1460 return -2;
1461 }
1462 }
1463 if (maininfo==nullptr) {
1465 }
1466 if (previnfo==nullptr) {
1468 } else {
1469 previnfo->fNext = leafinfo;
1471 }
1472 leafinfo = nullptr;
1473 current = &(work[0]);
1474 *current = 0;
1476 prevUseReferenceObject = false;
1477 useCollectionObject = false;
1478
1479 if (cl && cl->GetCollectionProxy()) {
1480 if (numberOfVarDim>1) {
1481 Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1482 cl->GetName());
1483 leafinfo = new TFormLeafInfo(cl,0,nullptr);
1484 useCollectionObject = true;
1485 } else if (numberOfVarDim==0) {
1487 leafinfo = new TFormLeafInfoCollection(cl,0,cl);
1489 } else if (numberOfVarDim==1) {
1491 leafinfo =
1493 (TStreamerElement*)nullptr,maininfo);
1494 previnfo->fNext = leafinfo;
1496 leafinfo = new TFormLeafInfoCollection(cl,0,cl);
1497
1498 fHasMultipleVarDim[code] = true;
1500 }
1501 previnfo->fNext = leafinfo;
1503 leafinfo = nullptr;
1504 }
1505 continue;
1506 } else if (right[i] == ')') {
1507 // We should have the end of a cast operator. Let's introduce a TFormLeafCast
1508 // in the chain.
1509 TClass * casted = (TClass*) ((int(--paran_level)>=0) ? castqueue.At(paran_level) : nullptr);
1510 if (casted) {
1512 fHasCast = true;
1513
1514 if (maininfo==nullptr) {
1516 }
1517 if (previnfo==nullptr) {
1519 } else {
1520 previnfo->fNext = leafinfo;
1522 }
1523 leafinfo = nullptr;
1524 current = &(work[0]);
1525 *current = 0;
1526
1527 cl = casted;
1528 continue;
1529
1530 }
1531 } else if (i > 0 && (right[i] == '.' || right[i] == '[' || right[i] == '\0') ) {
1532 // A delimiter happened let's see if what we have seen
1533 // so far does point to a data member.
1534 bool needClass = true;
1535 *current = '\0';
1536
1537 // skip it all if there is nothing to look at
1538 if (strlen(work)==0) continue;
1539
1542 if (work[0]=='@') {
1543 useReferenceObject = true;
1544 useCollectionObject = true;
1545 Int_t l = 0;
1546 for(l=0;work[l+1]!=0;++l) work[l] = work[l+1];
1547 work[l] = '\0';
1548 } else if (work[strlen(work)-1]=='@') {
1549 useReferenceObject = true;
1550 useCollectionObject = true;
1551 work[strlen(work)-1] = '\0';
1552 } else {
1553 useReferenceObject = false;
1554 useCollectionObject = false;
1555 }
1556
1557 bool mustderef = false;
1558 if ( !prevUseReferenceObject && cl && cl->GetReferenceProxy() ) {
1559 R__LoadBranch(leaf->GetBranch(), readentry, fQuickLoad);
1560 if ( !maininfo ) {
1562 if ( cl->GetReferenceProxy()->HasCounter() ) {
1564 }
1565 prevUseReferenceObject = false;
1566 } else {
1567 previnfo->fNext = new TFormLeafInfoReference(cl, element, offset);
1568 previnfo = previnfo->fNext;
1569 }
1571 cl = nullptr;
1572 for(Long64_t entry=0; entry<leaf->GetBranch()->GetEntries()-readentry; ++entry) {
1573 R__LoadBranch(leaf->GetBranch(), readentry+i, fQuickLoad);
1574 void *refobj = maininfo->GetValuePointer(leaf,0);
1575 if (refobj) {
1576 cl = refproxy->GetValueClass(refobj);
1577 }
1578 if ( cl ) break;
1579 }
1580 needClass = false;
1581 mustderef = true;
1582 }
1583 else if (!prevUseCollectionObject && cl == TClonesArray::Class()) {
1584 // We are not interested in the ClonesArray object but only
1585 // in its contents.
1586 // We need to retrieve the class of its content.
1587
1588 TBranch *clbranch = leaf->GetBranch();
1591 if (maininfo) {
1592 clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
1593 } else {
1594 // we have a unsplit TClonesArray leaves
1595 // or we did not yet match any of the sub-branches!
1596
1598 if (leaf->IsA()==TLeafObject::Class()) {
1599 // in this case mother_cl is not really used
1600 mother_cl = cl;
1601 } else {
1602 mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1603 }
1604
1606 // The dimension needs to be handled!
1608
1609 mustderef = true;
1612
1613 if (clbranch->GetListOfBranches()->GetLast()>=0) {
1614 if (clbranch->IsA() != TBranchElement::Class()) {
1615 Error("DefinedVariable","Unimplemented usage of ClonesArray");
1616 return -2;
1617 }
1618 //clbranch = ((TBranchElement*)clbranch)->GetMother();
1619 clones = (TClonesArray*)((TBranchElement*)clbranch)->GetObject();
1620 } else
1621 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1622 }
1623 // NOTE clones can be zero!
1624 if (clones==nullptr) {
1625 Warning("DefinedVariable",
1626 "TClonesArray object was not retrievable for %s!",
1627 name.Data());
1628 return -1;
1629 }
1630 TClass * inside_cl = clones->GetClass();
1631#if 1
1632 cl = inside_cl;
1633#else
1634/* Maybe we should make those test lead to warning messages */
1635 if (1 || inside_cl) cl = inside_cl;
1636 // if inside_cl is nul ... we have a problem of inconsistency :(
1637 if (0 && strlen(work)==0) {
1638 // However in this case we have NO content :(
1639 // so let get the number of objects
1640 //strcpy(work,"fLast");
1641 }
1642#endif
1643 } else if (!prevUseCollectionObject && cl && cl->GetCollectionProxy() ) {
1644
1645 // We are NEVER interested in the Collection object but only
1646 // in its contents.
1647 // We need to retrieve the class of its content.
1648
1649 TBranch *clbranch = leaf->GetBranch();
1651
1652 if (maininfo==nullptr) {
1653
1654 // we have a unsplit Collection leaf
1655 // or we did not yet match any of the sub-branches!
1656
1658 if (leaf->IsA()==TLeafObject::Class()) {
1659 // in this case mother_cl is not really used
1660 mother_cl = cl;
1661 } else {
1662 mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1663 }
1664
1667 // The dimension needs to be handled!
1669
1670 mustderef = true;
1673
1674 } //else if (clbranch->GetStreamerType()==0) {
1675
1676 //}
1677
1679
1680 if (!inside_cl) {
1681 Error("DefinedVariable","Could you not find the inner class for %s with coll type = %d",
1682 cl->GetName(),cl->GetCollectionProxy()->GetType());
1683 }
1684 if (!inside_cl && cl->GetCollectionProxy()->GetType() > 0) {
1685 Warning("DefinedVariable","No data member in content of %s in %s\n",
1686 cl->GetName(),name.Data());
1687 }
1688 cl = inside_cl;
1689 // if inside_cl is nul ... we have a problem of inconsistency.
1690 }
1691
1692 if (!cl) {
1693 if (leaf) leaf->GetBranch()->Print();
1694 Warning("DefinedVariable","Missing class for %s!",name.Data());
1695 } else {
1696 element = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1697 }
1698
1700 // We allow for looking for a data member inside a class inside
1701 // a TClonesArray without mentioning the TClonesArrays variable name
1702 TIter next( cl->GetStreamerInfo()->GetElements() );
1704 while ((curelem = (TStreamerElement*)next())) {
1705 if (curelem->GetClassPointer() == TClonesArray::Class()) {
1706 Int_t clones_offset = 0;
1707 ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),clones_offset);
1711 R__LoadBranch(leaf->GetBranch(),readentry,fQuickLoad);
1712
1713 if (previnfo) {
1714 previnfo->fNext = clonesinfo;
1715 clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
1716 previnfo->fNext = nullptr;
1717 } else {
1718 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1719 }
1720
1721 TClass *sub_cl = clones->GetClass();
1722 if (sub_cl) element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1723 delete clonesinfo;
1724
1725 if (element) {
1728 if (maininfo==nullptr) maininfo = leafinfo;
1729 if (previnfo==nullptr) previnfo = leafinfo;
1730 else {
1731 previnfo->fNext = leafinfo;
1733 }
1734 leafinfo = nullptr;
1735 cl = sub_cl;
1736 break;
1737 }
1738 } else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {
1739
1740 Int_t coll_offset = 0;
1741 ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),coll_offset);
1742
1743 TClass *sub_cl =
1744 curelem->GetClassPointer()->GetCollectionProxy()->GetValueClass();
1745 if (sub_cl) {
1746 element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1747 }
1748 if (element) {
1749 if (numberOfVarDim>1) {
1750 Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1751 curelem->GetName());
1753 useCollectionObject = true;
1754 } else if (numberOfVarDim==1) {
1756 leafinfo =
1759 fHasMultipleVarDim[code] = true;
1762 } else {
1765 }
1766 if (maininfo==nullptr) maininfo = leafinfo;
1767 if (previnfo==nullptr) previnfo = leafinfo;
1768 else {
1769 previnfo->fNext = leafinfo;
1771 }
1772 if (leafinfo->fNext) {
1773 previnfo = leafinfo->fNext;
1774 }
1775 leafinfo = nullptr;
1776 cl = sub_cl;
1777 break;
1778 }
1779 }
1780 }
1781
1782 }
1783
1784 if (element) {
1785 Int_t type = element->GetNewType();
1786 if (type<60 && type!=0) {
1787 // This is a basic type ...
1788 if (numberOfVarDim>=1 && type>40) {
1789 // We have a variable array within a variable array!
1791 fHasMultipleVarDim[code] = true;
1792 } else {
1793 if (leafinfo && type<=40 ) {
1794 leafinfo->AddOffset(offset,element);
1795 } else {
1797 }
1798 }
1799 } else {
1800 bool object = false;
1801 bool pointer = false;
1802 bool objarr = false;
1803 switch(type) {
1814 pointer = true;
1815 break;
1817 case TStreamerInfo::kAny :
1823 object = true;
1824 break;
1828 objarr = true;
1829 break;
1832 // Unsupported case.
1833 Error("DefinedVariable",
1834 "%s is a datamember of %s BUT is not yet of a supported type (%d)",
1835 right,cl ? cl->GetName() : "unknown class",type);
1836 return -2;
1837 default:
1838 // Unknown and Unsupported case.
1839 Error("DefinedVariable",
1840 "%s is a datamember of %s BUT is not of a unknown type (%d)",
1841 right,cl ? cl->GetName() : "unknown class",type);
1842 return -2;
1843 }
1844
1845 if (object && !useCollectionObject &&
1846 ( element->GetClassPointer() == TClonesArray::Class()
1847 || element->GetClassPointer()->GetCollectionProxy() ) )
1848 {
1849 object = false;
1850 }
1851 if (object && leafinfo) {
1852 leafinfo->AddOffset(offset,element);
1853 } else if (objarr) {
1854 // This is an embedded array of objects. We can not increase the offset.
1856 mustderef = true;
1857 } else {
1858
1859 if (!useCollectionObject && element->GetClassPointer() == TClonesArray::Class()) {
1860
1862 mustderef = true;
1863
1864 } else if (!useCollectionObject && element->GetClassPointer()
1865 && element->GetClassPointer()->GetCollectionProxy()) {
1866
1867 mustderef = true;
1868 if (numberOfVarDim>1) {
1869 Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1870 element->GetName());
1872 useCollectionObject = true;
1873 } else if (numberOfVarDim==1) {
1875 leafinfo =
1877
1878 fHasMultipleVarDim[code] = true;
1879 //numberOfVarDim += RegisterDimensions(code,leafinfo);
1880 //cl = cl->GetCollectionProxy()->GetValueClass();
1881
1882 //if (maininfo==0) maininfo = leafinfo;
1883 //if (previnfo==0) previnfo = leafinfo;
1884 //else {
1885 // previnfo->fNext = leafinfo;
1886 // previnfo = leafinfo;
1887 //}
1889 if (element->GetClassPointer()->GetCollectionProxy()->GetValueClass()==nullptr) {
1891 element->GetClassPointer()->GetCollectionProxy());
1892 if (leafinfo->fNext) leafinfo->fNext->fNext = info;
1893 else leafinfo->fNext = info;
1894 }
1895 } else {
1897
1898 TClass *elemCl = element->GetClassPointer();
1899 TClass *valueCl = elemCl->GetCollectionProxy()->GetValueClass();
1900 if (!maininfo) maininfo = leafinfo;
1901
1902 if (valueCl!=nullptr && valueCl->GetCollectionProxy()!=nullptr) {
1903
1905 if (previnfo==nullptr) previnfo = leafinfo;
1906 else {
1907 previnfo->fNext = leafinfo;
1909 }
1911 elemCl->GetCollectionProxy()->GetValueClass(),maininfo);
1912 //numberOfVarDim += RegisterDimensions(code,previnfo->fNext);
1913 fHasMultipleVarDim[code] = true;
1914 //previnfo = previnfo->fNext;
1916 valueCl);
1917 elemCl = valueCl;
1918 }
1919 if (elemCl->GetCollectionProxy() &&
1920 elemCl->GetCollectionProxy()->GetValueClass()==nullptr) {
1921 TFormLeafInfo *info = new TFormLeafInfoNumerical(elemCl->GetCollectionProxy());
1922 if (leafinfo->fNext) leafinfo->fNext->fNext = info;
1923 else leafinfo->fNext = info;
1924 }
1925 }
1926 } else if ( (object || pointer) && !useReferenceObject && element->GetClassPointer()->GetReferenceProxy() ) {
1927 TClass* c = element->GetClassPointer();
1928 R__LoadBranch(leaf->GetBranch(),readentry,fQuickLoad);
1929 if ( object ) {
1931 }
1932 else {
1934 leafinfo->fNext = new TFormLeafInfoReference(c, element, 0);
1935 }
1936 //if ( c->GetReferenceProxy()->HasCounter() ) {
1937 // numberOfVarDim += RegisterDimensions(code,-1);
1938 //}
1939 prevUseReferenceObject = false;
1940 needClass = false;
1941 mustderef = true;
1942 } else if (pointer) {
1943 // this is a pointer to be followed.
1945 mustderef = true;
1946 } else {
1947 // this is an embedded object.
1948 R__ASSERT(object);
1950 }
1951 }
1952 }
1953 } else {
1954 if (cl) Error("DefinedVariable","%s is not a datamember of %s",work,cl->GetName());
1955 // no else, we warned earlier that the class was missing.
1956 return -1;
1957 }
1958
1959 numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,useCollectionObject); // Note or useCollectionObject||prevUseColectionObject
1960 if (maininfo==nullptr) {
1962 }
1963 if (previnfo==nullptr) {
1965 } else if (previnfo!=leafinfo) {
1966 previnfo->fNext = leafinfo;
1968 }
1969 while (previnfo->fNext) previnfo = previnfo->fNext;
1970
1971 if ( right[i] != '\0' ) {
1972 if ( !needClass && mustderef ) {
1973 maininfo->SetBranch(leaf->GetBranch());
1974 char *ptr = (char*)maininfo->GetValuePointer(leaf,0);
1976 if ( !maininfo->IsReference() ) {
1977 for( TFormLeafInfo* inf = maininfo->fNext; inf; inf = inf->fNext ) {
1978 if ( inf->IsReference() ) {
1980 }
1981 }
1982 }
1983 else {
1985 }
1986 if ( refInfo ) {
1987 cl = refInfo->GetValueClass(ptr);
1988 if ( !cl ) {
1989 Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1990 return -1;
1991 }
1992 element = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1993 }
1994 else {
1995 Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1996 return -1;
1997 }
1998 }
1999 else if ( needClass ) {
2000 cl = element->GetClassPointer();
2001 }
2002 }
2003 if (mustderef) leafinfo = nullptr;
2004 current = &(work[0]);
2005 *current = 0;
2006 R__ASSERT(right[i] != '['); // We are supposed to have removed all dimensions already!
2007
2008 if (cl == TString::Class() && strcmp(right+i+1,"fData") == 0) {
2009 // For backward compatibility replace TString::fData which no longer exist
2010 // by a call to TString::Data()
2011 right = ".Data()";
2012 i = 0;
2013 nchname = strlen(right);
2014 }
2015
2016 } else
2017 *current++ = right[i];
2018 }
2019 if (maininfo) {
2021 if (leaf) fLookupType[code] = kDataMember;
2022 else fLookupType[code] = kTreeMember;
2023 }
2024 }
2025
2026 if (strlen(work)!=0) {
2027 // We have something left to analyze. Let's make this an error case!
2028 return -1;
2029 }
2030
2031 TClass *objClass = EvalClass(code);
2032 if (objClass && !useLeafCollectionObject && objClass->GetCollectionProxy() && objClass->GetCollectionProxy()->GetValueClass()) {
2033 TFormLeafInfo *last = nullptr;
2034 if ( SwitchToFormLeafInfo(code) ) {
2035
2036 last = (TFormLeafInfo*)fDataMembers.At(code);
2037
2038 if (!last) return action;
2039 while (last->fNext) { last = last->fNext; }
2040
2041 }
2042 if (last && last->GetClass() != objClass) {
2044 if (leaf->IsA()==TLeafObject::Class()) {
2045 // in this case mother_cl is not really used
2046 mother_cl = cl;
2047 } else {
2048 mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
2049 }
2050
2052 // The dimension needs to be handled!
2054 last->fNext = collectioninfo;
2055 }
2056 numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0
2057 objClass = objClass->GetCollectionProxy()->GetValueClass();
2058 }
2060
2061 TFormLeafInfo *last = nullptr;
2062 if ( SwitchToFormLeafInfo(code) ) {
2063
2064 last = (TFormLeafInfo*)fDataMembers.At(code);
2065
2066 if (!last) return action;
2067 while (last->fNext) { last = last->fNext; }
2068
2069 }
2070 const char *funcname = nullptr;
2071 if (objClass == TString::Class()) {
2072 funcname = "Data";
2073 //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2074 } else if (objClass == stdStringClass) {
2075 funcname = "c_str";
2076 //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2077 }
2078 if (funcname) {
2080 if (last) {
2082 } else {
2084 if (leaf) fLookupType[code] = kDataMember;
2085 else fLookupType[code] = kTreeMember;
2086 }
2087 }
2088 return kDefinedString;
2089 }
2090
2091 if (objClass) {
2092 TMethodCall *method = new TMethodCall(objClass, "AsDouble", "");
2093 if (method->IsValid()
2094 && (method->ReturnType() == TMethodCall::kLong || method->ReturnType() == TMethodCall::kDouble)) {
2095
2096 TFormLeafInfo *last = nullptr;
2097 if (SwitchToFormLeafInfo(code)) {
2098 last = (TFormLeafInfo*)fDataMembers.At(code);
2099 // Improbable case
2100 if (!last) {
2101 delete method;
2102 return action;
2103 }
2104 while (last->fNext) { last = last->fNext; }
2105 }
2106 if (last) {
2108 } else {
2110 if (leaf) fLookupType[code] = kDataMember;
2111 else fLookupType[code] = kTreeMember;
2112 }
2113
2114 return kDefinedVariable;
2115 }
2116 delete method;
2117 method = new TMethodCall(objClass, "AsString", "");
2118 if (method->IsValid()
2119 && method->ReturnType() == TMethodCall::kString) {
2120
2121 TFormLeafInfo *last = nullptr;
2122 if (SwitchToFormLeafInfo(code)) {
2123 last = (TFormLeafInfo*)fDataMembers.At(code);
2124 // Improbable case
2125 if (!last) {
2126 delete method;
2127 return action;
2128 }
2129 while (last->fNext) { last = last->fNext; }
2130 }
2131 if (last) {
2133 } else {
2135 if (leaf) fLookupType[code] = kDataMember;
2136 else fLookupType[code] = kTreeMember;
2137 }
2138
2139 //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2140 return kDefinedString;
2141 }
2142 if (method->IsValid()
2143 && method->ReturnType() == TMethodCall::kOther) {
2144
2146 if ((rcl == TString::Class() || rcl == stdStringClass) ) {
2147
2148 TFormLeafInfo *last = nullptr;
2149 if (SwitchToFormLeafInfo(code)) {
2150 last = (TFormLeafInfo*)fDataMembers.At(code);
2151 // Improbable case
2152 if (!last) {
2153 delete method;
2154 return action;
2155 }
2156 while (last->fNext) { last = last->fNext; }
2157 }
2158 if (last) {
2160 last = last->fNext;
2161 } else {
2163 fDataMembers.AddAtAndExpand(last,code);
2164 if (leaf) fLookupType[code] = kDataMember;
2165 else fLookupType[code] = kTreeMember;
2166 }
2167
2168 objClass = rcl;
2169
2170 const char *funcname = nullptr;
2171 if (objClass == TString::Class()) {
2172 funcname = "Data";
2173 } else if (objClass == stdStringClass) {
2174 funcname = "c_str";
2175 }
2176 if (funcname) {
2177 method = new TMethodCall(objClass, funcname, "");
2179 }
2180 return kDefinedString;
2181 }
2182 }
2183 delete method;
2184 }
2185
2186 return action;
2187}
2188
2189////////////////////////////////////////////////////////////////////////////////
2190/// Look for the leaf corresponding to the start of expression.
2191/// It returns the corresponding leaf if any.
2192/// It also modify the following arguments:
2193///
2194/// - leftover: contain from expression that was not used to determine the leaf
2195/// - final:
2196/// * paran_level: number of un-matched open parenthesis
2197/// * cast_queue: list of cast to be done
2198/// * aliases: list of aliases used
2199/// - Return <0 in case of failure
2200///
2201/// - Return 0 if a leaf has been found
2202/// - Return 2 if info about the TTree itself has been requested.
2203
2204Int_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)
2205{
2206 // Later on we will need to read one entry, let's make sure
2207 // it is a real entry.
2208 if (fTree->GetTree()==nullptr) {
2209 fTree->LoadTree(0);
2210 if (fTree->GetTree()==nullptr) return -1;
2211 }
2212 Long64_t readentry = fTree->GetTree()->GetReadEntry();
2213 if (readentry < 0) readentry=0;
2214 const char *cname = expression;
2215 char first[kMaxLen]; first[0] = '\0';
2216 char second[kMaxLen*2]; second[0] = '\0';
2217 char right[kMaxLen*2]; right[0] = '\0';
2218 char work[kMaxLen]; work[0] = '\0';
2219 char left[kMaxLen]; left[0] = '\0';
2220 char scratch[kMaxLen*5];
2221 char scratch2[kMaxLen*5];
2222 std::string currentname;
2223 Int_t previousdot = 0;
2224 char *current;
2225 TLeaf *tmp_leaf=nullptr;
2226 TBranch *branch=nullptr, *tmp_branch=nullptr;
2228 Int_t i;
2229 bool foundAtSign = false;
2230 bool startWithParan = false;
2231
2232 for (i=0, current = &(work[0]); i<=nchname && !final;i++ ) {
2233 // We will treated the terminator as a token.
2234 *current++ = cname[i];
2235
2236 if (cname[i] == '(') {
2237 ++paran_level;
2238
2239 if (current==work+1) {
2240 // If the expression starts with a parenthesis, we are likely
2241 // to have a cast operator inside.
2242 startWithParan = true;
2243 current--;
2244 }
2245 continue;
2246 //i++;
2247 //while( cname[i]!=')' && cname[i] ) {
2248 // *current++ = cname[i++];
2249 //}
2250 //*current++ = cname[i];
2251 ////*current = 0;
2252 //continue;
2253 }
2254 if (cname[i] == ')') {
2255 if (paran_level==0) {
2256 Error("DefinedVariable","Unmatched parenthesis in %s",fullExpression);
2257 return -1;
2258 }
2259 paran_level--;
2260
2261 if (startWithParan) {
2262 startWithParan = false; // the next match wont be against the starting parenthesis.
2263
2264 // Let's see if work is a classname and thus we have a cast.
2265 *(--current) = 0;
2266 TString cast_name = gInterpreter->TypeName(work);
2268 if (cast_cl) {
2269 // We must have a cast
2270 castqueue.AddAtAndExpand(cast_cl,paran_level);
2271 current = &(work[0]);
2272 *current = 0;
2273 // Warning("DefinedVariable","Found cast to %s",cast_fullExpression);
2274 continue;
2275 } else if (gROOT->GetType(cast_name)) {
2276 // We reset work
2277 current = &(work[0]);
2278 *current = 0;
2279 Warning("DefinedVariable",
2280 "Casting to primary types like \"%s\" is not supported yet",cast_name.Data());
2281 continue;
2282 }
2283 *(current++)=')';
2284 }
2285
2286 *current='\0';
2287 char *params = strchr(work,'(');
2288 if (params) {
2289 *params = 0; params++;
2290
2291 if (branch && !leaf) {
2292 // We have a branch but not a leaf. We are likely to have found
2293 // the top of split branch.
2294 if (BranchHasMethod(nullptr, branch, work, params, readentry)) {
2295 //fprintf(stderr, "Does have a method %s for %s.\n", work, branch->GetName());
2296 }
2297 }
2298
2299 // What we have so far might be a member function of one of the
2300 // leaves that are not split (for example "GetNtrack" for the Event class).
2302 TLeaf* leafcur = nullptr;
2303 while (!leaf && (leafcur = (TLeaf*) next())) {
2304 TBranch* br = leafcur->GetBranch();
2305 bool yes = BranchHasMethod(leafcur, br, work, params, readentry);
2306 if (yes) {
2307 leaf = leafcur;
2308 //fprintf(stderr, "Does have a method %s for %s found in leafcur %s.\n", work, leafcur->GetBranch()->GetName(), leafcur->GetName());
2309 }
2310 }
2311 if (!leaf) {
2312 // Check for an alias.
2313 if (strlen(left) && left[strlen(left)-1]=='.') left[strlen(left)-1]=0;
2314 const char *aliasValue = fTree->GetAlias(left);
2315 if (aliasValue && strcspn(aliasValue, "()[]+*/-%&!=<>|") == strlen(aliasValue) &&
2317 // First check whether we are using this alias recursively (this would
2318 // lead to an infinite recursion).
2319 if (find(aliasUsed.begin(),
2320 aliasUsed.end(),
2321 left) != aliasUsed.end()) {
2322 Error("DefinedVariable",
2323 "The substitution of the branch alias \"%s\" by \"%s\" in \"%s\" failed\n"\
2324 "\tbecause \"%s\" is used [recursively] in its own definition!",
2325 left,aliasValue,fullExpression,left);
2326 return -3;
2327 }
2328 aliasUsed.push_back(left);
2330 newExpression += (cname+strlen(left));
2333 if (res<0) {
2334 Error("DefinedVariable",
2335 "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue);
2336 return -3;
2337 }
2338 return res;
2339 }
2340
2341 // This is actually not really any error, we probably received something
2342 // like "abs(some_val)", let ROOT::v5::TFormula decompose it first.
2343 return -1;
2344 }
2345 // if (!leaf->InheritsFrom(TLeafObject::Class()) ) {
2346 // If the leaf that we found so far is not a TLeafObject then there is
2347 // nothing we would be able to do.
2348 // Error("DefinedVariable","Need a TLeafObject to call a function!");
2349 // return -1;
2350 //}
2351 // We need to recover the info not used.
2352 strlcpy(right,work,2*kMaxLen);
2353 strncat(right,"(",2*kMaxLen-1-strlen(right));
2354 strncat(right,params,2*kMaxLen-1-strlen(right));
2355 final = true;
2356
2357 // Record in 'i' what we consumed
2358 i += 2; // open and close parentheses
2359
2360 // we reset work
2361 current = &(work[0]);
2362 *current = 0;
2363 break;
2364 }
2365 }
2366 if (cname[i] == '.' || cname[i] == '\0' || cname[i] == ')') {
2367 // A delimiter happened let's see if what we have seen
2368 // so far does point to a leaf.
2369 *current = '\0';
2370
2371 Int_t len = strlen(work);
2372 if (work[0]=='@') {
2373 foundAtSign = true;
2374 Int_t l = 0;
2375 for(l=0;work[l+1]!=0;++l) work[l] = work[l+1];
2376 work[l] = '\0';
2377 --current;
2378 } else if (len>=2 && work[len-2]=='@') {
2379 foundAtSign = true;
2380 work[len-2] = cname[i];
2381 work[len-1] = '\0';
2382 --current;
2383 } else {
2384 foundAtSign = false;
2385 }
2386
2387 if (left[0]==0) strlcpy(left,work,kMaxLen);
2388 if (!leaf && !branch) {
2389 // So far, we have not found a matching leaf or branch.
2390 strlcpy(first,work,kMaxLen);
2391
2392 std::string treename(first);
2393 if (!treename.empty() && treename[treename.size()-1]=='.') {
2394 treename.erase(treename.size()-1);
2395 }
2396 if (treename== "This" /* || treename == fTree->GetName() */ ) {
2397 // Request info about the TTree object itself,
2401 if (cname[i]) leftover = &(cname[i+1]);
2402 return 2;
2403 }
2404 // The following would allow to access the friend by name
2405 // however, it would also prevent the access of the leaves
2406 // within the friend. We could use the '@' notation here
2407 // however this would not be aesthetically pleasing :(
2408 // What we need to do, is add the ability to look ahead to
2409 // the next 'token' to decide whether we to access the tree
2410 // or its leaf.
2411 //} else {
2412 // TTree *tfriend = fTree->GetFriend(treename.c_str());
2413 // TTree *realtree = fTree->GetTree();
2414 // if (!tfriend && realtree != fTree){
2415 // // If it is a chain and we did not find a friend,
2416 // // let's try with the internal tree.
2417 // tfriend = realtree->GetFriend(treename.c_str());
2418 // }
2419 // if (tfriend) {
2420 // TNamed *named = new TNamed(treename.c_str(),tfriend->GetName());
2421 // fLeafNames.AddAtAndExpand(named,fNcodes);
2422 // fLeaves.AddAtAndExpand(tfriend,fNcodes);
2423 // if (cname[i]) leftover = &(cname[i+1]);
2424 // return 2;
2425 // }
2426 //}
2427
2428 branch = fTree->FindBranch(first);
2429 leaf = fTree->FindLeaf(first);
2430
2431 // Now look with the delimiter removed (we looked with it first
2432 // because a dot is allowed at the end of some branches).
2433 if (cname[i]) first[strlen(first)-1]='\0';
2434 if (!branch) branch = fTree->FindBranch(first);
2435 if (!leaf) leaf = fTree->FindLeaf(first);
2436 TClass* cl = nullptr;
2437 if ( branch && branch->InheritsFrom(TBranchElement::Class()) ) {
2438 int offset=0;
2440 TStreamerInfo* info = bElt->GetInfo();
2441 TStreamerElement* element = info ? info->GetStreamerElement(first,offset) : nullptr;
2442 if (element) cl = element->GetClassPointer();
2443 if ( cl && !cl->GetReferenceProxy() ) cl = nullptr;
2444 }
2445 if ( cl ) { // We have a reference class here....
2446 final = true;
2448 // we reset work
2449 current = &(work[0]);
2450 *current = 0;
2451 }
2452 else if (branch && (foundAtSign || cname[i] != 0) ) {
2453 // Since we found a branch and there is more information in the name,
2454 // we do NOT look at the 'IsOnTerminalBranch' status of the leaf
2455 // we found ... yet!
2456
2457 if (leaf==nullptr) {
2458 // Note we do not know (yet?) what (if anything) to do
2459 // for a TBranchObject branch.
2460 if (branch->InheritsFrom(TBranchElement::Class()) ) {
2461 Int_t type = ((TBranchElement*)branch)->GetType();
2462 if ( type == 3 || type ==4) {
2463 // We have a Collection branch.
2464 leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
2465 if (foundAtSign) {
2467 foundAtSign = false;
2468 current = &(work[0]);
2469 *current = 0;
2470 ++i;
2471 break;
2472 }
2473 }
2474 }
2475 }
2476
2477 // we reset work
2479 foundAtSign = false;
2480 current = &(work[0]);
2481 *current = 0;
2482 } else if (leaf || branch) {
2483 if (leaf && branch) {
2484 // We found both a leaf and branch matching the request name
2485 // let's see which one is the proper one to use! (On annoying case
2486 // is that where the same name is repeated ( varname.varname )
2487
2488 // We always give priority to the branch
2489 // leaf = 0;
2490 }
2491 if (leaf && leaf->IsOnTerminalBranch()) {
2492 // This is a non-object leaf, it should NOT be specified more except for
2493 // dimensions.
2494 final = true;
2495 }
2496 // we reset work
2497 current = &(work[0]);
2498 *current = 0;
2499 } else {
2500 // What we have so far might be a data member of one of the
2501 // leaves that are not split (for example "fNtrack" for the Event class.
2503 if (leafcur) {
2504 leaf = leafcur;
2505 branch = leaf->GetBranch();
2506 if (leaf->IsOnTerminalBranch()) {
2507 final = true;
2508 strlcpy(right,first,kMaxLen);
2509 //We need to put the delimiter back!
2510 if (foundAtSign) strncat(right,"@",2*kMaxLen-1-strlen(right));
2511 if (cname[i]=='.') strncat(right,".",2*kMaxLen-1-strlen(right));
2512
2513 // We reset work
2514 current = &(work[0]);
2515 *current = 0;
2516 };
2517 } else if (cname[i] == '.') {
2518 // If we have a branch that match a name preceded by a dot
2519 // then we assume we are trying to drill down the branch
2520 // Let look if one of the top level branch has a branch with the name
2521 // we are looking for.
2523 TIter next( fTree->GetListOfBranches() );
2524 while(!branch && (branchcur=(TBranch*)next()) ) {
2525 branch = branchcur->FindBranch(first);
2526 }
2527 if (branch) {
2528 // We reset work
2529 current = &(work[0]);
2530 *current = 0;
2531 }
2532 }
2533 }
2534 } else { // correspond to if (leaf || branch)
2535 if (final) {
2536 Error("DefinedVariable", "Unexpected control flow!");
2537 return -1;
2538 }
2539
2540 // No dot is allowed in subbranches and leaves, so
2541 // we always remove it in the present case.
2542 if (cname[i]) work[strlen(work)-1] = '\0';
2543 snprintf(scratch,sizeof(scratch),"%s.%s",first,work);
2544 snprintf(scratch2,sizeof(scratch2),"%s.%s.%s",first,second,work);
2545
2546 if (previousdot) {
2548 }
2549
2550 // First look for the current 'word' in the list of
2551 // leaf of the
2552 if (branch) {
2553 tmp_leaf = branch->FindLeaf(work);
2554 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch);
2555 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch2);
2556 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(currentname.c_str());
2557 }
2558 if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
2559 // This is a non-object leaf, it should NOT be specified more except for
2560 // dimensions.
2561 final = true;
2562 }
2563
2564 if (branch) {
2565 tmp_branch = branch->FindBranch(work);
2566 if (!tmp_branch) tmp_branch = branch->FindBranch(scratch);
2567 if (!tmp_branch) tmp_branch = branch->FindBranch(scratch2);
2568 if (!tmp_branch) tmp_branch = branch->FindBranch(currentname.c_str());
2569 }
2570 if (tmp_branch) {
2572
2573 // NOTE: Should we look for a leaf within here?
2574 if (!final) {
2575 tmp_leaf = branch->FindLeaf(work);
2576 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch);
2577 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch2);
2578 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(currentname.c_str());
2579 if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
2580 // This is a non-object leaf, it should NOT be specified
2581 // more except for dimensions.
2582 final = true;
2583 leaf = tmp_leaf;
2584 }
2585 }
2586 }
2587 if (tmp_leaf) {
2588 // Something was found.
2589 if (second[0]) strncat(second,".",2*kMaxLen-1-strlen(second));
2590 strncat(second,work,2*kMaxLen-1-strlen(second));
2591 leaf = tmp_leaf;
2593 foundAtSign = false;
2594
2595 // we reset work
2596 current = &(work[0]);
2597 *current = 0;
2598 } else {
2599 //We need to put the delimiter back!
2600 if (strlen(work)) {
2601 if (foundAtSign) {
2603 work[where] = '@';
2604 work[where+1] = cname[i];
2605 ++current;
2606 previousdot = where+1;
2607 } else {
2609 work[strlen(work)] = cname[i];
2610 }
2611 } else --current;
2612 }
2613 }
2614 }
2615 }
2616
2617 // Copy the left over for later use.
2618 if (strlen(work)) {
2619 strncat(right,work,2*kMaxLen-1-strlen(right));
2620 }
2621
2622 if (i<nchname) {
2623 if (strlen(right) && right[strlen(right)-1]!='.' && cname[i]!='.') {
2624 // In some cases we remove a little too fast the period, we add
2625 // it back if we need. It is assumed that 'right' and the rest of
2626 // the name was cut by a delimiter, so this should be safe.
2627 strncat(right,".",2*kMaxLen-1-strlen(right));
2628 }
2629 strncat(right,&cname[i],2*kMaxLen-1-strlen(right));
2630 }
2631
2632 if (!final && branch) {
2633 if (!leaf) {
2634 leaf = (TLeaf*)branch->GetListOfLeaves()->UncheckedAt(0);
2635 if (!leaf) return -1;
2636 }
2637 final = leaf->IsOnTerminalBranch();
2638 }
2639
2640 if (leaf && leaf->InheritsFrom(TLeafObject::Class()) ) {
2641 if (strlen(right)==0) strlcpy(right,work,2*kMaxLen);
2642 }
2643
2644 if (leaf==nullptr && left[0]!=0) {
2645 if (left[strlen(left)-1]=='.') left[strlen(left)-1]=0;
2646
2647 // Check for an alias.
2648 const char *aliasValue = fTree->GetAlias(left);
2649 if (aliasValue && strcspn(aliasValue, "()[]+*/-%&!=<>|") == strlen(aliasValue) && !IsNumberConstant(aliasValue)) {
2650 // First check whether we are using this alias recursively (this would
2651 // lead to an infinite recursion).
2652 if (find(aliasUsed.begin(),
2653 aliasUsed.end(),
2654 left) != aliasUsed.end()) {
2655 Error("DefinedVariable",
2656 "The substitution of the branch alias \"%s\" by \"%s\" in \"%s\" failed\n"\
2657 "\tbecause \"%s\" is used [recursively] in its own definition!",
2658 left,aliasValue,fullExpression,left);
2659 return -3;
2660 }
2661 aliasUsed.push_back(left);
2663 newExpression += (cname+strlen(left));
2666 if (res<0) {
2667 Error("DefinedVariable",
2668 "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue);
2669 return -3;
2670 }
2671 return res;
2672 }
2673 }
2674 leftover = right;
2675
2676 return 0;
2677}
2678
2679////////////////////////////////////////////////////////////////////////////////
2680/// Check if name is in the list of Tree/Branch leaves.
2681///
2682/// This member function redefines the function in ROOT::v5::TFormula
2683/// If a leaf has a name corresponding to the argument name, then
2684/// returns a new code.
2685///
2686/// A TTreeFormula may contain more than one variable.
2687/// For each variable referenced, the pointers to the corresponding
2688/// branch and leaf is stored in the object arrays fBranches and fLeaves.
2689///
2690/// name can be :
2691/// - Leaf_Name (simple variable or data member of a ClonesArray)
2692/// - Branch_Name.Leaf_Name
2693/// - Branch_Name.Method_Name
2694/// - Leaf_Name[index]
2695/// - Branch_Name.Leaf_Name[index]
2696/// - Branch_Name.Leaf_Name[index1]
2697/// - Branch_Name.Leaf_Name[][index2]
2698/// - Branch_Name.Leaf_Name[index1][index2]
2699///
2700/// New additions:
2701/// - Branch_Name.Leaf_Name[OtherLeaf_Name]
2702/// - Branch_Name.Datamember_Name
2703/// - '.' can be replaced by '->'
2704///
2705/// and
2706/// - Branch_Name[index1].Leaf_Name[index2]
2707/// - Leaf_name[index].Action().OtherAction(param)
2708/// - Leaf_name[index].Action()[val].OtherAction(param)
2709///
2710/// The expected returned values are
2711/// - -2 : the name has been recognized but won't be usable
2712/// - -1 : the name has not been recognized, or is too long, or tree does not exist.
2713/// - >=0 : the name has been recognized, return the internal code for this name.
2714
2716{
2717
2719 if (!fTree) return -1;
2720
2721 fNpar = 0;
2722 if (name.Length() > kMaxLen) {
2723 Error("TTreeFormula", "The length of the variable name (%d) exceeds the maximum allowed (%d)", name.Length(), kMaxLen);
2724 return -1;
2725 }
2726 Int_t i,k;
2727
2728 if (name == "Entry$") {
2729 Int_t code = fNcodes++;
2730 fCodes[code] = 0;
2731 fLookupType[code] = kIndexOfEntry;
2732 return code;
2733 }
2734 if (name == "LocalEntry$") {
2735 Int_t code = fNcodes++;
2736 fCodes[code] = 0;
2738 return code;
2739 }
2740 if (name == "Entries$") {
2741 Int_t code = fNcodes++;
2742 fCodes[code] = 0;
2743 fLookupType[code] = kEntries;
2746 return code;
2747 }
2748 if (name == "LocalEntries$") {
2749 Int_t code = fNcodes++;
2750 fCodes[code] = 0;
2751 fLookupType[code] = kLocalEntries;
2752 SetBit(kNeedEntries); // FIXME: necessary?
2753 fManager->SetBit(kNeedEntries); // FIXME: necessary?
2754 return code;
2755 }
2756 if (name == "Iteration$") {
2757 Int_t code = fNcodes++;
2758 fCodes[code] = 0;
2759 fLookupType[code] = kIteration;
2760 return code;
2761 }
2762 if (name == "Length$") {
2763 Int_t code = fNcodes++;
2764 fCodes[code] = 0;
2765 fLookupType[code] = kLength;
2766 return code;
2767 }
2768 static const char *lenfunc = "Length$(";
2769 if (strncmp(name.Data(),"Length$(",strlen(lenfunc))==0
2770 && name[name.Length()-1]==')') {
2771
2772 TString subform = name.Data()+strlen(lenfunc);
2773 subform.Remove( subform.Length() - 1 );
2774 TTreeFormula *lengthForm = new TTreeFormula("lengthForm",subform,fTree);
2776 Int_t code = fNcodes++;
2777 fCodes[code] = 0;
2778 fLookupType[code] = kLengthFunc;
2779 return code;
2780 }
2781 static const char *minfunc = "Min$(";
2782 if (strncmp(name.Data(),"Min$(",strlen(minfunc))==0
2783 && name[name.Length()-1]==')') {
2784
2785 TString subform = name.Data()+strlen(minfunc);
2786 subform.Remove( subform.Length() - 1 );
2787 TTreeFormula *minForm = new TTreeFormula("minForm",subform,fTree);
2789 Int_t code = fNcodes++;
2790 fCodes[code] = 0;
2791 fLookupType[code] = kMin;
2792 return code;
2793 }
2794 static const char *maxfunc = "Max$(";
2795 if (strncmp(name.Data(),"Max$(",strlen(maxfunc))==0
2796 && name[name.Length()-1]==')') {
2797
2798 TString subform = name.Data()+strlen(maxfunc);
2799 subform.Remove( subform.Length() - 1 );
2800 TTreeFormula *maxForm = new TTreeFormula("maxForm",subform,fTree);
2802 Int_t code = fNcodes++;
2803 fCodes[code] = 0;
2804 fLookupType[code] = kMax;
2805 return code;
2806 }
2807 static const char *sumfunc = "Sum$(";
2808 if (strncmp(name.Data(),"Sum$(",strlen(sumfunc))==0
2809 && name[name.Length()-1]==')') {
2810
2811 TString subform = name.Data()+strlen(sumfunc);
2812 subform.Remove( subform.Length() - 1 );
2813 TTreeFormula *sumForm = new TTreeFormula("sumForm",subform,fTree);
2815 Int_t code = fNcodes++;
2816 fCodes[code] = 0;
2817 fLookupType[code] = kSum;
2818 return code;
2819 }
2820
2821
2822
2823 // Check for $Alt(expression1,expression2)
2824 Int_t res = DefineAlternate(name.Data());
2825 if (res!=0) {
2826 // There was either a syntax error or we found $Alt
2827 if (res<0) return res;
2828 action = res;
2829 return 0;
2830 }
2831
2832 // Find the top level leaf and deal with dimensions
2833
2834 char cname[kMaxLen]; strlcpy(cname,name.Data(),kMaxLen);
2835 char dims[kMaxLen]; dims[0] = '\0';
2836
2837 bool final = false;
2838
2839 UInt_t paran_level = 0;
2841
2842 // First, it is easier to remove all dimensions information from 'cname'
2844 for(i=0,k=0; i<cnamelen; ++i, ++k) {
2845 if (cname[i] == '[') {
2846 int bracket = i;
2847 int bracket_level = 1;
2848 int j;
2849 for (j=++i; j<cnamelen && (bracket_level>0 || cname[j]=='['); j++, i++) {
2850 if (cname[j]=='[') bracket_level++;
2851 else if (cname[j]==']') bracket_level--;
2852 }
2853 if (bracket_level != 0) {
2854 //Error("DefinedVariable","Bracket unbalanced");
2855 return -1;
2856 }
2858 //k += j-bracket;
2859 }
2860 if (i!=k) cname[k] = cname[i];
2861 }
2862 cname[k]='\0';
2863
2864 bool useLeafCollectionObject = false;
2866 TLeaf *leaf = nullptr;
2867 {
2868 std::vector<std::string> aliasSofar = fAliasesUsed;
2870 }
2871 if (res<0) return res;
2872
2873 if (!leaf && res!=2) {
2874 // Check for an alias.
2875 const char *aliasValue = fTree->GetAlias(cname);
2876 if (aliasValue) {
2877 // First check whether we are using this alias recursively (this would
2878 // lead to an infinite recursion).
2879 if (find(fAliasesUsed.begin(),
2880 fAliasesUsed.end(),
2881 cname) != fAliasesUsed.end()) {
2882 Error("DefinedVariable",
2883 "The substitution of the alias \"%s\" by \"%s\" failed\n"\
2884 "\tbecause \"%s\" is recursively used in its own definition!",
2886 return -3;
2887 }
2888
2889 if (strcspn(aliasValue, "()[]+*/-%&!=<>|") != strlen(aliasValue) || IsNumberConstant(aliasValue)) {
2890 // If the alias contains an operator, we need to use a nested formula
2891 // (since DefinedVariable must only add one entry to the operation's list).
2892
2893 // Need to check the aliases used so far
2894 std::vector<std::string> aliasSofar = fAliasesUsed;
2895 aliasSofar.push_back( cname );
2896
2898 if (dims[0]) {
2899 subValue += dims;
2900 }
2901
2902 TTreeFormula *subform = new TTreeFormula(cname,subValue,fTree,aliasSofar); // Need to pass the aliases used so far.
2903
2904 if (subform->GetNdim()==0) {
2905 delete subform;
2906 Error("DefinedVariable",
2907 "The substitution of the alias \"%s\" by \"%s\" failed.",cname,aliasValue);
2908 return -3;
2909 }
2910
2913
2914 if (subform->IsString()) {
2916 return 0;
2917 } else {
2918 action = kAlias;
2919 return 0;
2920 }
2921 } else { /* assumes strcspn(aliasValue,"[]")!=strlen(aliasValue) */
2923 thisAlias += dims;
2925 if (aliasRes<0) {
2926 // We failed but DefinedVariable has not printed why yet.
2927 // and because we want those to be printed _before_ the notice
2928 // of the failure of the substitution, we need to print them here.
2929 if (aliasRes==-1) {
2930 Error("Compile", " Bad numerical expression : \"%s\"",thisAlias.Data());
2931 } else if (aliasRes==-2) {
2932 Error("Compile", " Part of the Variable \"%s\" exists but some of it is not accessible or useable",thisAlias.Data());
2933
2934 }
2935 Error("DefinedVariable",
2936 "The substitution of the alias \"%s\" by \"%s\" failed.",cname,aliasValue);
2937 return -3;
2938 }
2939 return aliasRes;
2940 }
2941 }
2942 }
2943
2944
2945 if (leaf || res==2) {
2946
2947 if (leaf && leaf->GetBranch() && leaf->GetBranch()->TestBit(kDoNotProcess)) {
2948 Error("DefinedVariable","the branch \"%s\" has to be enabled to be used",leaf->GetBranch()->GetName());
2949 return -2;
2950 }
2951
2952 Int_t code = fNcodes++;
2953
2954 // If needed will now parse the indexes specified for
2955 // arrays.
2956 if (dims[0]) {
2957 char *current = &( dims[0] );
2958 Int_t dim = 0;
2960 Int_t index;
2962 while (current) {
2963 current++;
2964 if (current[0] == ']') {
2965 fIndexes[code][dim] = -1; // Loop over all elements;
2966 } else {
2967 TString tempIndex(current);
2968 auto closePos = tempIndex.First(']');
2969 if (closePos != -1)
2971 if (tempIndex.IsDigit() && (scanindex = sscanf(current, "%d", &index)) && scanindex == 1) {
2972 fIndexes[code][dim] = index;
2973 } else {
2974 fIndexes[code][dim] = -2; // Index is calculated via a variable.
2975 varindex = current;
2976 char *end = (char*)(varindex.Data());
2977 for(char bracket_level = 0;*end!=0;end++) {
2978 if (*end=='[') bracket_level++;
2979 if (bracket_level==0 && *end==']') break;
2980 if (*end==']') bracket_level--;
2981 }
2982 *end = '\0';
2983 fVarIndexes[code][dim] = new TTreeFormula("index_var",
2984 varindex,
2985 fTree);
2986 if (fVarIndexes[code][dim]->GetNdim() == 0) {
2987 // Parsing failed for the index, let's stop here ....
2988 return -1;
2989 }
2990 current += strlen(varindex)+1; // move to the end of the index array
2991 }
2992 }
2993 dim ++;
2994 if (dim >= kMAXFORMDIM) {
2995 // NOTE: test that dim this is NOT too big!!
2996 break;
2997 }
2998 current = (char*)strstr( current, "[" );
2999 }
3000 }
3001
3002 // Now that we have cleaned-up the expression, let's compare it to the content
3003 // of the leaf!
3004
3006 if (res<0) return res;
3007 if (res>0) action = res;
3008 return code;
3009 }
3010
3011//*-*- May be a graphical cut ?
3012 TCutG *gcut = (TCutG*)gROOT->GetListOfSpecials()->FindObject(name.Data());
3013 if (gcut) {
3014 if (gcut->GetObjectX()) {
3015 if(!gcut->GetObjectX()->InheritsFrom(TTreeFormula::Class()))
3016 gcut->SetObjectX(nullptr);
3017 }
3018 if (gcut->GetObjectY()) {
3019 if(!gcut->GetObjectY()->InheritsFrom(TTreeFormula::Class()))
3020 gcut->SetObjectY(nullptr);
3021 }
3022
3023 Int_t code = fNcodes;
3024
3025 if (strlen(gcut->GetVarX()) && strlen(gcut->GetVarY()) ) {
3026
3027 TTreeFormula *fx = new TTreeFormula("f_x",gcut->GetVarX(),fTree);
3028 gcut->SetObjectX(fx);
3029
3030 TTreeFormula *fy = new TTreeFormula("f_y",gcut->GetVarY(),fTree);
3031 gcut->SetObjectY(fy);
3032
3033 fCodes[code] = -2;
3034
3035 } else if (strlen(gcut->GetVarX())) {
3036
3037 // Let's build the equivalent formula:
3038 // min(gcut->X) <= VarX <= max(gcut->Y)
3039 Double_t min = 0;
3040 Double_t max = 0;
3041 Int_t n = gcut->GetN();
3042 Double_t *x = gcut->GetX();
3043 min = max = x[0];
3044 for(Int_t i2 = 1; i2<n; i2++) {
3045 if (x[i2] < min) min = x[i2];
3046 if (x[i2] > max) max = x[i2];
3047 }
3048 TString formula = "(";
3049 formula += min;
3050 formula += "<=";
3051 formula += gcut->GetVarX();
3052 formula += " && ";
3053 formula += gcut->GetVarX();
3054 formula += "<=";
3055 formula += max;
3056 formula += ")";
3057
3058 TTreeFormula *fx = new TTreeFormula("f_x",formula.Data(),fTree);
3059 gcut->SetObjectX(fx);
3060
3061 fCodes[code] = -1;
3062
3063 } else {
3064
3065 Error("DefinedVariable","Found a TCutG without leaf information (%s)",
3066 gcut->GetName());
3067 return -1;
3068
3069 }
3070
3072 fNcodes++;
3073 fLookupType[code] = -1;
3074 return code;
3075 }
3076
3077 //may be an entrylist
3078 TEntryList *elist = dynamic_cast<TEntryList*> (gDirectory->Get(name.Data()));
3079 if (elist) {
3080 Int_t code = fNcodes;
3081 fCodes[code] = 0;
3082 fExternalCuts.AddAtAndExpand(elist, code);
3083 fNcodes++;
3084 fLookupType[code] = kEntryList;
3085 return code;
3086
3087 }
3088
3089 return -1;
3090}
3091
3092////////////////////////////////////////////////////////////////////////////////
3093/// Return the leaf (if any) which contains an object containing
3094/// a data member which has the name provided in the arguments.
3095
3097{
3098 TClass * cl = nullptr;
3100 TFormLeafInfo* clonesinfo = nullptr;
3101 TLeaf *leafcur;
3102 while ((leafcur = (TLeaf*)nextleaf())) {
3103 // The following code is used somewhere else, we need to factor it out.
3104
3105 // Here since we are interested in data member, we want to consider only
3106 // 'terminal' branch and leaf.
3107 cl = nullptr;
3108 if (leafcur->InheritsFrom(TLeafObject::Class()) &&
3109 leafcur->GetBranch()->GetListOfBranches()->Last()==nullptr) {
3111 cl = lobj->GetClass();
3112 } else if (leafcur->InheritsFrom(TLeafElement::Class()) && leafcur->IsOnTerminalBranch()) {
3114 if (lElem->IsOnTerminalBranch()) {
3115 TBranchElement *branchEl = (TBranchElement *)leafcur->GetBranch();
3116 Int_t type = branchEl->GetStreamerType();
3117 if (type==-1) {
3118 cl = branchEl->GetInfo() ? branchEl->GetInfo()->GetClass() : nullptr;
3119 } else if (type>60 || type==0) {
3120 // Case of an object data member. Here we allow for the
3121 // variable name to be omitted. Eg, for Event.root with split
3122 // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
3123 TStreamerElement* element = branchEl->GetInfo()->GetElement(branchEl->GetID());
3124 if (element) cl = element->GetClassPointer();
3125 else cl = nullptr;
3126 }
3127 }
3128
3129 }
3130 if (clonesinfo) { delete clonesinfo; clonesinfo = nullptr; }
3131 if (cl == TClonesArray::Class()) {
3132 // We have a unsplit TClonesArray leaves
3133 // In this case we assume that cl is the class in which the TClonesArray
3134 // belongs.
3137
3138 TBranch *branch = leafcur->GetBranch();
3139 if ( branch->IsA()==TBranchElement::Class()
3140 && ((TBranchElement*)branch)->GetType()==31) {
3141
3142 // We have an unsplit TClonesArray as part of a split TClonesArray!
3143
3144 // Let's not dig any further. If the user really wants a data member
3145 // inside the nested TClonesArray, it has to specify it explicitly.
3146
3147 continue;
3148
3149 } else {
3150 bool toplevel = (branch == branch->GetMother());
3152 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leafcur,0);
3153 }
3154 if (clones) cl = clones->GetClass();
3155 } else if (cl && cl->GetCollectionProxy()) {
3156
3157 // We have a unsplit Collection leaves
3158 // In this case we assume that cl is the class in which the TClonesArray
3159 // belongs.
3160
3161 TBranch *branch = leafcur->GetBranch();
3162 if ( branch->IsA()==TBranchElement::Class()
3163 && ((TBranchElement*)branch)->GetType()==41) {
3164
3165 // We have an unsplit Collection as part of a split Collection!
3166
3167 // Let's not dig any further. If the user really wants a data member
3168 // inside the nested Collection, it has to specify it explicitly.
3169
3170 continue;
3171
3172 } else {
3174 }
3175 cl = cl->GetCollectionProxy()->GetValueClass();
3176 }
3177 if (cl) {
3178 // Now that we have the class, let's check if the topchoice is of its datamember
3179 // or if the nextchoice is a datamember of one of its datamember.
3180 Int_t offset;
3182 TStreamerElement* element = info?info->GetStreamerElement(topchoice,offset):nullptr;
3183 if (!element) {
3186 while ((curelem = (TStreamerElement*)nextel())) {
3187
3188 if (curelem->GetClassPointer() == TClonesArray::Class()) {
3189 // In case of a TClonesArray we need to load the data and read the
3190 // clonesArray object before being able to look into the class inside.
3191 // We need to do that because we are never interested in the TClonesArray
3192 // itself but only in the object inside.
3193 TBranch *branch = leafcur->GetBranch();
3194 TFormLeafInfo *leafinfo = nullptr;
3195 if (clonesinfo) {
3197 } else if (branch->IsA()==TBranchElement::Class()
3198 && ((TBranchElement*)branch)->GetType()==31) {
3199 // Case of a sub branch of a TClonesArray
3201 TStreamerInfo *bel_info = branchEl->GetInfo();
3202 TClass * mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
3204 bel_info->GetElement(branchEl->GetID());
3206 }
3207
3208 Int_t clones_offset = 0;
3209 ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),clones_offset);
3211 if (leafinfo)
3212 if (leafinfo->fNext) leafinfo->fNext->fNext = sub_clonesinfo;
3213 else leafinfo->fNext = sub_clonesinfo;
3214 else leafinfo = sub_clonesinfo;
3215
3217
3218 TClonesArray * clones = (TClonesArray*)leafinfo->GetValuePointer(leafcur,0);
3219
3220 delete leafinfo; clonesinfo = nullptr;
3221 // If TClonesArray object does not exist we have no information, so let go
3222 // on. This is a weakish test since the TClonesArray object might exist in
3223 // the next entry ... In other word, we ONLY rely on the information available
3224 // in entry #0.
3225 if (!clones) continue;
3226 TClass *sub_cl = clones->GetClass();
3227
3228 // Now that we finally have the inside class, let's query it.
3229 element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(nextchoice,offset);
3230 if (element) break;
3231 } // if clones array
3232 else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {
3233
3234 TClass *sub_cl = curelem->GetClassPointer()->GetCollectionProxy()->GetValueClass();
3235
3236 while(sub_cl && sub_cl->GetCollectionProxy())
3237 sub_cl = sub_cl->GetCollectionProxy()->GetValueClass();
3238
3239 // Now that we finally have the inside class, let's query it.
3240 if (sub_cl) element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(nextchoice,offset);
3241 if (element) break;
3242
3243 }
3244 } // loop on elements
3245 }
3246 if (element) break;
3247 else cl = nullptr;
3248 }
3249 }
3250 delete clonesinfo;
3251 if (cl) {
3252 return leafcur;
3253 } else {
3254 return nullptr;
3255 }
3256}
3257
3258////////////////////////////////////////////////////////////////////////////////
3259/// Return the leaf (if any) of the tree with contains an object of a class
3260/// having a method which has the name provided in the argument.
3261
3262bool TTreeFormula::BranchHasMethod(TLeaf* leafcur, TBranch* branch, const char* method, const char* params, Long64_t readentry) const
3263{
3264 TClass *cl = nullptr;
3265 TLeafObject* lobj = nullptr;
3266
3267 // Since the user does not want this branch to be loaded anyway, we just
3268 // skip it. This prevents us from warning the user that the method might
3269 // be on a disabled branch. However, and more usefully, this allows the
3270 // user to avoid error messages from branches that cannot be currently
3271 // read without warnings/errors.
3272
3273 if (branch->TestBit(kDoNotProcess)) {
3274 return false;
3275 }
3276
3277 // FIXME: The following code is used somewhere else, we need to factor it out.
3278 if (branch->InheritsFrom(TBranchObject::Class())) {
3279 lobj = (TLeafObject*) branch->GetListOfLeaves()->At(0);
3280 cl = lobj->GetClass();
3281 } else if (branch->InheritsFrom(TBranchElement::Class())) {
3283 Int_t type = branchEl->GetStreamerType();
3284 if (type == -1) {
3285 cl = branchEl->GetInfo() ? branchEl->GetInfo()->GetClass() : nullptr;
3286 } else if (type > 60) {
3287 // Case of an object data member. Here we allow for the
3288 // variable name to be omitted. Eg, for Event.root with split
3289 // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
3290 TStreamerElement* element = branchEl->GetInfo()->GetElement(branchEl->GetID());
3291 if (element) {
3292 cl = element->GetClassPointer();
3293 } else {
3294 cl = nullptr;
3295 }
3296 if ((cl == TClonesArray::Class()) && (branchEl->GetType() == 31)) {
3297 // we have a TClonesArray inside a split TClonesArray,
3298 // Let's not dig any further. If the user really wants a data member
3299 // inside the nested TClonesArray, it has to specify it explicitly.
3300 cl = nullptr;
3301 }
3302 // NOTE do we need code for Collection here?
3303 }
3304 }
3305
3306 if (cl == TClonesArray::Class()) {
3307 // We might be try to call a method of the top class inside a
3308 // TClonesArray.
3309 // Since the leaf was not terminal, we might have a split or
3310 // unsplit and/or top leaf/branch.
3311 TClonesArray* clones = nullptr;
3313 if (branch->InheritsFrom(TBranchObject::Class())) {
3314 clones = (TClonesArray*) lobj->GetObject();
3315 } else if (branch->InheritsFrom(TBranchElement::Class())) {
3316 // We do not know exactly where the leaf of the TClonesArray is
3317 // in the hierarchy but we still need to get the correct class
3318 // holder.
3320 if (bc == bc->GetMother()) {
3321 // Top level branch
3322 //clones = *((TClonesArray**) bc->GetAddress());
3323 clones = (TClonesArray*) bc->GetObject();
3324 } else if (!leafcur || !leafcur->IsOnTerminalBranch()) {
3325 TStreamerElement* element = bc->GetInfo()->GetElement(bc->GetID());
3326 if (element->IsaPointer()) {
3327 clones = *((TClonesArray**) bc->GetAddress());
3328 //clones = *((TClonesArray**) bc->GetObject());
3329 } else {
3330 //clones = (TClonesArray*) bc->GetAddress();
3331 clones = (TClonesArray*) bc->GetObject();
3332 }
3333 }
3334 if (!clones) {
3337 mother_cl = bc->GetInfo()->GetClass();
3339 // if (!leafcur) { leafcur = (TLeaf*) branch->GetListOfLeaves()->At(0); }
3340 clones = (TClonesArray*) clonesinfo->GetLocalValuePointer(leafcur, 0);
3341 // cl = clones->GetClass();
3342 delete clonesinfo;
3343 }
3344 } else {
3345 Error("BranchHasMethod","A TClonesArray was stored in a branch type no yet support (i.e. neither TBranchObject nor TBranchElement): %s",branch->IsA()->GetName());
3346 return false;
3347 }
3348 cl = clones ? clones->GetClass() : nullptr;
3349 } else if (cl && cl->GetCollectionProxy()) {
3350 cl = cl->GetCollectionProxy()->GetValueClass();
3351 }
3352
3353 if (cl) {
3354 if (cl->GetClassInfo()) {
3355 if (cl->GetMethodAllAny(method)) {
3356 // Let's try to see if the function we found belongs to the current
3357 // class. Note that this implementation currently can not work if
3358 // one the argument is another leaf or data member of the object.
3359 // (Anyway we do NOT support this case).
3360 TMethodCall methodcall(cl, method, params);
3361 if (methodcall.GetMethod()) {
3362 // We have a method that works.
3363 // We will use it.
3364 return true;
3365 }
3366 }
3367 }
3368 }
3369
3370 return false;
3371}
3372
3373////////////////////////////////////////////////////////////////////////////////
3374/// Now let calculate what physical instance we really need.
3375/// Some redundant code is used to speed up the cases where
3376/// they are no dimensions.
3377///
3378/// We know that instance is less that fCumulUsedSize[0] so
3379/// we can skip the modulo when virt_dim is 0.
3380
3382 Int_t real_instance = 0;
3384
3385 bool check = false;
3386 if (codeindex<0) {
3387 codeindex = 0;
3388 check = true;
3389 }
3390
3391 TFormLeafInfo * info = nullptr;
3392 Int_t max_dim = fNdimensions[codeindex];
3393 if ( max_dim ) {
3394 virt_dim = 0;
3395 max_dim--;
3396
3397 if (!fManager->fMultiVarDim) {
3398 if (fIndexes[codeindex][0]>=0) {
3400 } else {
3403 if (fIndexes[codeindex][0]==-2) {
3404 // NOTE: Should we check that this is a valid index?
3405 if (check) {
3408 // out of bounds
3409 return fNdata[0]+1;
3410 }
3411 }
3413 // Force the loading of the index.
3415 }
3417 if (local_index<0) {
3418 Error("EvalInstance","Index %s is out of bound (%d) in formula %s",
3421 GetTitle());
3422 return fNdata[0]+1;
3423 }
3424 }
3426 virt_dim ++;
3427 }
3428 } else {
3429 // NOTE: We assume that ONLY the first dimension of a leaf can have a variable
3430 // size AND contain the index for the size of yet another sub-dimension.
3431 // I.e. a variable size array inside a variable size array can only have its
3432 // size vary with the VERY FIRST physical dimension of the leaf.
3433 // Thus once the index of the first dimension is found, all other dimensions
3434 // are fixed!
3435
3436 // NOTE: We could unroll some of this loops to avoid a few tests.
3439 // if (info && info->GetVarDim()==-1) info = 0;
3440 }
3442
3443 switch (fIndexes[codeindex][0]) {
3444 case -2:
3446 // Force the loading of the index.
3448 }
3450 if (local_index<0) {
3451 Error("EvalInstance","Index %s is out of bound (%d) in formula %s",
3454 GetTitle());
3455 local_index = 0;
3456 }
3457 break;
3458 case -1: {
3462 }
3466
3468 if (maxloop == 0) {
3469 local_index--;
3470 instance = fNdata[0]+1; // out of bounds.
3471 if (check) return fNdata[0]+1;
3472 } else {
3473 do {
3475 local_index++;
3476 } while( instance >= virt_accum && local_index<maxloop);
3477 local_index--;
3478 // update the cache
3481
3482 if (local_index==(maxloop-1) && (instance >= virt_accum)) {
3483 instance = fNdata[0]+1; // out of bounds.
3484 if (check) return fNdata[0]+1;
3485 } else {
3488 } else {
3489 instance = fNdata[0]+1; // out of bounds.
3490 if (check) return fNdata[0]+1;
3491 }
3492 }
3493 }
3494 virt_dim ++;
3495 }
3496 break;
3497 default:
3499 }
3500
3501 // Inform the (appropriate) MultiVarLeafInfo that the clones array index is
3502 // local_index.
3503
3506 } else {
3508 }
3509 for(Int_t d = kMAXFORMDIM-1; d>0; d--) {
3510 if (fManager->fVarDims[d]) {
3512 } else {
3514 }
3515 }
3516 if (info) {
3517 // When we have multiple variable dimensions, the LeafInfo only expect
3518 // the instance after the primary index has been set.
3519 info->SetPrimaryIndex(local_index);
3520 real_instance = 0;
3521
3522 // Let's update fCumulSizes for the rest of the code.
3523 Int_t vdim = info->GetVarDim();
3524 Int_t isize = info->GetSize(local_index);
3525 if (fIndexes[codeindex][vdim]>=0) {
3526 info->SetSecondaryIndex(fIndexes[codeindex][vdim]);
3527 }
3528 if (isize!=1 && fIndexes[codeindex][vdim]>isize) {
3529 // We are out of bounds!
3530 return fNdata[0]+1;
3531 }
3533 for(Int_t k=vdim -1; k>0; --k) {
3535 }
3536 } else {
3538 }
3539 }
3540 if (max_dim>0) {
3541 for (Int_t dim = 1; dim < max_dim; dim++) {
3542 if (fIndexes[codeindex][dim]>=0) {
3544 } else {
3549 } else {
3551 }
3552 if (fIndexes[codeindex][dim]==-2) {
3553 // NOTE: Should we check that this is a valid index?
3555 // Force the loading of the index.
3557 }
3559 if (local_index<0 ||
3561 Error("EvalInstance","Index %s is out of bound (%d/%d) in formula %s",
3565 GetTitle());
3567 }
3568 }
3570 virt_dim ++;
3571 }
3572 }
3573 if (fIndexes[codeindex][max_dim]>=0) {
3574 if (!info) real_instance += fIndexes[codeindex][max_dim];
3575 } else {
3579 } else {
3581 }
3582 if (info && local_index>=fCumulSizes[codeindex][max_dim]) {
3583 // We are out of bounds! [Multiple var dims, See same message a few line above]
3584 return fNdata[0]+1;
3585 }
3586 if (fIndexes[codeindex][max_dim]==-2) {
3588 // Force the loading of the index.
3589 fVarIndexes[codeindex][max_dim]->LoadBranches();
3590 }
3592 if (local_index<0 ||
3593 local_index>=fCumulSizes[codeindex][max_dim]) {
3594 Error("EvalInstance","Index %s is of out bound (%d/%d) in formula %s",
3595 fVarIndexes[codeindex][max_dim]->GetTitle(),
3597 fCumulSizes[codeindex][max_dim],
3598 GetTitle());
3599 local_index = fCumulSizes[codeindex][max_dim]-1;
3600 }
3601 }
3603 }
3604 } // if (max_dim-1>0)
3605 } // if (max_dim)
3606
3607 return real_instance;
3608}
3609
3610////////////////////////////////////////////////////////////////////////////////
3611/// Evaluate the class of this treeformula.
3612///
3613/// If the 'value' of this formula is a simple pointer to an object,
3614/// this function returns the TClass corresponding to its type.
3615
3617{
3618 if (fNoper != 1 || fNcodes <=0 ) return nullptr;
3619
3620 return EvalClass(0);
3621}
3622
3623////////////////////////////////////////////////////////////////////////////////
3624/// Evaluate the class of the operation oper.
3625///
3626/// If the 'value' in the requested operation is a simple pointer to an object,
3627/// this function returns the TClass corresponding to its type.
3628
3630{
3632 switch(fLookupType[oper]) {
3633 case kDirect: {
3634 if (leaf->IsA()==TLeafObject::Class()) {
3635 return ((TLeafObject*)leaf)->GetClass();
3636 } else if ( leaf->IsA()==TLeafElement::Class()) {
3637 TBranchElement * branch = (TBranchElement*)((TLeafElement*)leaf)->GetBranch();
3638 TStreamerInfo * info = branch->GetInfo();
3639 Int_t id = branch->GetID();
3640 if (id>=0) {
3641 if (info==nullptr || !info->IsCompiled()) {
3642 // we probably do not have a way to know the class of the object.
3643 return nullptr;
3644 }
3645 TStreamerElement* elem = (TStreamerElement*)info->GetElement(id);
3646 if (elem==nullptr) {
3647 // we probably do not have a way to know the class of the object.
3648 return nullptr;
3649 } else {
3650 return elem->GetClass();
3651 }
3652 } else return TClass::GetClass( branch->GetClassName() );
3653 } else {
3654 return nullptr;
3655 }
3656 }
3657 case kMethod: return nullptr; // kMethod is deprecated so let's no waste time implementing this.
3658 case kTreeMember:
3659 case kDataMember: {
3661 if (!obj) return nullptr;
3662 return ((TFormLeafInfo*)obj)->GetClass();
3663 }
3664
3665 default: return nullptr;
3666 }
3667
3668
3669}
3670
3671////////////////////////////////////////////////////////////////////////////////
3672/// Evaluate this treeformula.
3673///
3674/// Return the address of the object pointed to by the formula.
3675/// Return 0 if the formula is not a single object
3676/// The object type can be retrieved using by call EvalClass();
3677
3679{
3680 if (fNoper != 1 || fNcodes <=0 ) return nullptr;
3681
3682
3683 switch (fLookupType[0]) {
3684 case kIndexOfEntry:
3685 case kIndexOfLocalEntry:
3686 case kEntries:
3687 case kLocalEntries:
3688 case kLength:
3689 case kLengthFunc:
3690 case kIteration:
3691 case kEntryList:
3692 return nullptr;
3693 }
3694
3696
3698
3699 if (instance==0 || fNeedLoading) {
3700 fNeedLoading = false;
3701 R__LoadBranch(leaf->GetBranch(),
3702 leaf->GetBranch()->GetTree()->GetReadEntry(),
3703 fQuickLoad);
3704 }
3705 else if (real_instance>=fNdata[0]) return nullptr;
3706 if (fAxis) {
3707 return nullptr;
3708 }
3709 switch(fLookupType[0]) {
3710 case kDirect: {
3711 if (real_instance) {
3712 Warning("EvalObject","Not yet implement for kDirect and arrays (for %s).\nPlease contact the developers",GetName());
3713 }
3714 return leaf->GetValuePointer();
3715 }
3716 case kMethod: return GetValuePointerFromMethod(0,leaf);
3717 case kTreeMember:
3718 case kDataMember: return ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->GetValuePointer(leaf,real_instance);
3719 default: return nullptr;
3720 }
3721
3722
3723}
3724
3725
3726////////////////////////////////////////////////////////////////////////////////
3727/// Eval the instance as a string.
3728
3730{
3731 const Int_t kMAXSTRINGFOUND = 10;
3732 const char *stringStack[kMAXSTRINGFOUND];
3733
3734 if (fNoper==1 && fNcodes>0 && IsString()) {
3736
3738
3739 if (instance==0 || fNeedLoading) {
3740 fNeedLoading = false;
3741 TBranch *branch = leaf->GetBranch();
3742 R__LoadBranch(branch,branch->GetTree()->GetReadEntry(),fQuickLoad);
3743 } else if (real_instance>=fNdata[0]) {
3744 return nullptr;
3745 }
3746
3747 if (fLookupType[0]==kDirect) {
3748 return (char*)leaf->GetValuePointer();
3749 } else {
3750 return (char*)GetLeafInfo(0)->GetValuePointer(leaf,real_instance);
3751 }
3752 }
3753
3755
3756 return stringStack[0];
3757}
3758
3759#define TT_EVAL_INIT \
3760 TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0); \
3761 \
3762 const Int_t real_instance = GetRealInstance(instance,0); \
3763 \
3764 if (instance==0) fNeedLoading = true; \
3765 if (real_instance>=fNdata[0]) return TMath::SignalingNaN(); \
3766 \
3767 /* Since the only operation in this formula is reading this branch, \
3768 we are guaranteed that this function is first called with instance==0 and \
3769 hence we are guaranteed that the branch is always properly read */ \
3770 \
3771 if (fNeedLoading) { \
3772 fNeedLoading = false; \
3773 TBranch *br = leaf->GetBranch(); \
3774 if (br && br->GetTree()) { \
3775 Long64_t tentry = br->GetTree()->GetReadEntry(); \
3776 R__LoadBranch(br,tentry,fQuickLoad); \
3777 } else { \
3778 Error("TTreeFormula::TT_EVAL_INIT", \
3779 "Could not init branch associated to this leaf (%s).", leaf->GetName()); \
3780 } \
3781 } \
3782 \
3783 if (fAxis) { \
3784 char * label; \
3785 /* This portion is a duplicate (for speed reason) of the code \
3786 located in the main for loop at "a tree string" (and in EvalStringInstance) */ \
3787 if (fLookupType[0]==kDirect) { \
3788 label = (char*)leaf->GetValuePointer(); \
3789 } else { \
3790 label = (char*)GetLeafInfo(0)->GetValuePointer(leaf,instance); \
3791 } \
3792 Int_t bin = fAxis->FindBin(label); \
3793 return bin-0.5; \
3794 }
3795
3796#define TREE_EVAL_INIT \
3797 const Int_t real_instance = GetRealInstance(instance,0); \
3798 \
3799 if (real_instance>=fNdata[0]) return TMath::SignalingNaN(); \
3800 \
3801 if (fAxis) { \
3802 char * label; \
3803 /* This portion is a duplicate (for speed reason) of the code \
3804 located in the main for loop at "a tree string" (and in EvalStringInstance) */ \
3805 label = (char*)GetLeafInfo(0)->GetValuePointer((TLeaf*)0x0,instance); \
3806 Int_t bin = fAxis->FindBin(label); \
3807 return bin-0.5; \
3808 }
3809
3810#define TT_EVAL_INIT_LOOP \
3811 TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(code); \
3812 \
3813 /* Now let calculate what physical instance we really need. */ \
3814 const Int_t real_instance = GetRealInstance(instance,code); \
3815 \
3816 if (willLoad) { \
3817 TBranch *branch = (TBranch*)fBranches.UncheckedAt(code); \
3818 if (branch) { \
3819 if (branch->GetTree()) { \
3820 Long64_t treeEntry = branch->GetTree()->GetReadEntry(); \
3821 R__LoadBranch(branch,treeEntry,fQuickLoad); \
3822 } else { \
3823 Error("TTreeFormula::TT_EVAL_INIT_LOOP", \
3824 "Could not init branch associated to this leaf (%s).", leaf->GetName()); \
3825 } \
3826 } else if (fDidBooleanOptimization) { \
3827 branch = leaf->GetBranch(); \
3828 if (branch->GetTree()) { \
3829 Long64_t treeEntry = branch->GetTree()->GetReadEntry(); \
3830 if (branch->GetReadEntry() != treeEntry) branch->GetEntry( treeEntry ); \
3831 } else { \
3832 Error("TTreeFormula::TT_EVAL_INIT_LOOP", \
3833 "Could not init branch associated to this leaf (%s).", leaf->GetName()); \
3834 } \
3835 } \
3836 } else { \
3837 /* In the cases where we are behind (i.e. right of) a potential boolean optimization \
3838 this tree variable reading may have not been executed with instance==0 which would \
3839 result in the branch being potentially not read in. */ \
3840 if (fDidBooleanOptimization) { \
3841 TBranch *br = leaf->GetBranch(); \
3842 if (br->GetTree()) { \
3843 Long64_t treeEntry = br->GetTree()->GetReadEntry(); \
3844 if (br->GetReadEntry() != treeEntry) br->GetEntry( treeEntry ); \
3845 } else { \
3846 Error("TTreeFormula::TT_EVAL_INIT_LOOP", \
3847 "Could not init branch associated to this leaf (%s).", leaf->GetName()); \
3848 } \
3849 } \
3850 } \
3851 if (real_instance>=fNdata[code]) return TMath::SignalingNaN();
3852
3853#define TREE_EVAL_INIT_LOOP \
3854 /* Now let calculate what physical instance we really need. */ \
3855 const Int_t real_instance = GetRealInstance(instance,code); \
3856 \
3857 if (real_instance>=fNdata[code]) return TMath::SignalingNaN();
3858
3859
3860template<typename T> T Summing(TTreeFormula *sum) {
3861 Int_t len = sum->GetNdata();
3862 T res = 0;
3863 for (int i=0; i<len; ++i) res += sum->EvalInstance<T>(i);
3864 return res;
3865}
3866
3867template<typename T> T FindMin(TTreeFormula *arr) {
3868 Int_t len = arr->GetNdata();
3869 T res = 0;
3870 if (len) {
3871 res = arr->EvalInstance<T>(0);
3872 for (int i=1; i<len; ++i) {
3873 T val = arr->EvalInstance<T>(i);
3874 if (val < res) {
3875 res = val;
3877 }
3878 }
3879 return res;
3880}
3881
3882template<typename T> T FindMax(TTreeFormula *arr) {
3883 Int_t len = arr->GetNdata();
3884 T res = 0;
3885 if (len) {
3886 res = arr->EvalInstance<T>(0);
3887 for (int i=1; i<len; ++i) {
3888 T val = arr->EvalInstance(i);
3889 if (val > res) {
3890 res = val;
3892 }
3893 }
3894 return res;
3895}
3896
3897template<typename T> T FindMin(TTreeFormula *arr, TTreeFormula *condition) {
3898 Int_t len = arr->GetNdata();
3899 T res = 0;
3900 if (len) {
3901 int i = 0;
3902 T condval;
3903 do {
3904 condval = condition->EvalInstance<T>(i);
3905 ++i;
3906 } while (!condval && i<len);
3907 if (!condval && i==len) {
3908 return 0;
3909 }
3910 if (i!=1) {
3911 // Insure the loading of the branch.
3912 arr->EvalInstance<T>(0);
3913 }
3914 // Now we know that i>0 && i<len and cond==true
3915 res = arr->EvalInstance<T>(i-1);
3916 for (; i<len; ++i) {
3917 condval = condition->EvalInstance<T>(i);
3918 if (condval) {
3919 T val = arr->EvalInstance<T>(i);
3920 if (val < res) {
3921 res = val;
3922 }
3924 }
3925 }
3926 return res;
3927}
3928
3929template<typename T> T FindMax(TTreeFormula *arr, TTreeFormula *condition) {
3930 Int_t len = arr->GetNdata();
3931 T res = 0;
3932 if (len) {
3933 int i = 0;
3934 T condval;
3935 do {
3936 condval = condition->EvalInstance<T>(i);
3937 ++i;
3938 } while (!condval && i<len);
3939 if (!condval && i==len) {
3940 return 0;
3941 }
3942 if (i!=1) {
3943 // Insure the loading of the branch.
3944 arr->EvalInstance<T>(0);
3945 }
3946 // Now we know that i>0 && i<len and cond==true
3947 res = arr->EvalInstance<T>(i-1);
3948 for (; i<len; ++i) {
3949 condval = condition->EvalInstance<T>(i);
3950 if (condval) {
3951 T val = arr->EvalInstance<T>(i);
3952 if (val > res) {
3953 res = val;
3954 }
3955 }
3956 }
3957 }
3958 return res;
3959}
3960
3961namespace {
3962
3963template <typename T> T fmod_local(T x, T y) { return fmod(x,y); }
3964template <> Long64_t fmod_local(Long64_t x, Long64_t y) { return fmod((LongDouble_t)x,(LongDouble_t)y); }
3966template<typename T> inline void SetMethodParam(TMethodCall *method, T p) { method->SetParam(p); }
3967template<> void SetMethodParam(TMethodCall *method, LongDouble_t p) { method->SetParam((Double_t)p); }
3968
3969}
3970
3971template<typename T> inline T TTreeFormula::GetConstant(Int_t k) { return fConst[k]; }
3972template<> inline LongDouble_t TTreeFormula::GetConstant(Int_t k) {
3973 if( !fConstLD ) {
3974 // create LD version of the constants list by rescanning all literals used in the expression
3976 for (Int_t op=0; op<fNoper ; ++op) {
3977 const Int_t oper = GetOper()[op];
3978 if( (oper >> kTFOperShift) == kConstant ) {
3979 int i = (oper & kTFOperMask);
3980 if( !strncmp(fExpr[op], "0x", 2) || !strncmp(fExpr[op], "0X", 2) ) {
3981 ULong64_t val;
3982 sscanf( fExpr[op], "%llx", &val );
3983 fConstLD[i] = (LongDouble_t)val;
3984 } else {
3985 sscanf( fExpr[op], "%Lg", &fConstLD[i] );
3987 }
3988 }
3989 }
3990 return fConstLD[k];
3991}
3993
3994////////////////////////////////////////////////////////////////////////////
3995/// \brief Evaluate this treeformula
3996/// \tparam T The type used to interpret the numbers then used for the operations
3997/// \param instance iteration instance
3998/// \param stringStackArg formula as string
3999/// \return the result of the evaluation, or a signaling NaN if out of bounds
4000///
4001/// \warning Care has to be taken before calling this function with std::vector
4002/// or dynamically sized objects, rather than plain fixed-size arrays.
4003/// For example, this works without problems:
4004/// ~~~{.cpp}
4005/// TTree t("t", "t");
4006/// Float_t x[2]{};
4007/// t.Branch("xa", &x, "x[2]/F");
4008/// x[1] = 1;
4009/// t.Fill();
4010/// x[1] = 2;
4011/// t.Fill();
4012/// t.Scan();
4013/// TTreeFormula tfx("tfx", "xa[1]", &t);
4014/// t.GetEntry(0);
4015/// tfx.EvalInstance()
4016/// t.GetEntry(1);
4017/// tfx.EvalInstance()
4018/// ~~~
4019/// But the following fails (independently on whether the size changed or not between entries):
4020/// ~~~{.cpp}
4021/// TTree t("t", "t");
4022/// vector<Short_t> v;
4023/// t.Branch("vec", &v);
4024/// v.push_back(2);
4025/// v.push_back(3);
4026/// t.Fill();
4027/// v.clear();
4028/// v.push_back(4);
4029/// v.push_back(5);
4030/// t.Fill();
4031/// t.Scan();
4032/// TTreeFormula tfv1("tfv1", "vec[1]", &t);
4033/// TTreeFormula tfv("tfv", "vec", &t);
4034/// t.GetEntry(0);
4035/// tfv1.EvalInstance()
4036/// tfv.EvalInstance(1)
4037/// t.GetEntry(1);
4038/// tfv1.EvalInstance()
4039/// tfv.EvalInstance(1)
4040/// ~~~
4041/// To prevent this, when working with objects with dynamic size for each entry, one needs
4042/// to mimick what TTree::Scan does, i.e. to check the value of
4043/// `GetNdata()` before calling `EvalInstance()`:
4044/// ~~~{.cpp}
4045/// t.GetEntry(0);
4046/// if (tfv1.GetNdata() > 0)
4047/// tfv1.EvalInstance()
4048/// if (tfv.GetNdata() > 1)
4049/// tfv.EvalInstance(1)
4050/// t.GetEntry(1);
4051/// if (tfv1.GetNdata() > 0)
4052/// tfv1.EvalInstance()
4053/// if (tfv.GetNdata() > 1)
4054/// tfv.EvalInstance(1)
4055/// ~~~
4056/// Note that for `tfv1`, even if the index is fixed in the formula and even if each entry
4057/// had the same std::vector size, since the formula contains a branch with theoretically variable size,
4058/// one must check GetNData() as there might 0 or 1 answers. Since even with fixed index,
4059/// the collection might be too small to fulfill it.
4060/// TTreeFormula::GetMultiplicity tells you (indirectly) whether you need to call GetNData or not for a given formula.
4061
4062template<typename T>
4064{
4065// Note that the redundancy and structure in this code is tailored to improve
4066// efficiencies.
4068 if (fNoper == 1 && fNcodes > 0) {
4069
4070 switch (fLookupType[0]) {
4071 case kDirect: {
4073 return leaf->GetTypedValue<T>(real_instance);
4074 }
4075 case kMethod: {
4077 ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->SetBranch(leaf->GetBranch());
4078 return GetValueFromMethod(0,leaf);
4079 }
4080 case kDataMember: {
4082 ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->SetBranch(leaf->GetBranch());
4084 }
4085 case kTreeMember: {
4088 }
4089 case kIndexOfEntry: return (T)fTree->GetReadEntry();
4090 case kIndexOfLocalEntry: return (T)fTree->GetTree()->GetReadEntry();
4091 case kEntries: return (T)fTree->GetEntries();
4092 case kLocalEntries: return (T)fTree->GetTree()->GetEntries();
4093 case kLength: return fManager->fNdata;
4094 case kLengthFunc: return ((TTreeFormula*)fAliases.UncheckedAt(0))->GetNdata();
4095 case kIteration: return instance;
4096 case kSum: return Summing<T>((TTreeFormula*)fAliases.UncheckedAt(0));
4097 case kMin: return FindMin<T>((TTreeFormula*)fAliases.UncheckedAt(0));
4098 case kMax: return FindMax<T>((TTreeFormula*)fAliases.UncheckedAt(0));
4099 case kEntryList: {
4100 TEntryList *elist = (TEntryList*)fExternalCuts.At(0);
4101 return elist->Contains(fTree->GetTree()->GetReadEntry());
4102 }
4103 case -1: break;
4104 }
4105 switch (fCodes[0]) {
4106 case -2: {
4108 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
4109 TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
4111 fx->ResetLoading();
4112 fy->ResetLoading();
4113 }
4114 T xcut = fx->EvalInstance<T>(instance);
4115 T ycut = fy->EvalInstance<T>(instance);
4116 return gcut->IsInside(xcut,ycut);
4117 }
4118 case -1: {
4120 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
4122 fx->ResetLoading();
4123 }
4124 return fx->EvalInstance<T>(instance);
4125 }
4126 default: return TMath::SignalingNaN();
4127 }
4128 }
4129
4130 T tab[kMAXFOUND];
4131 const Int_t kMAXSTRINGFOUND = 10;
4132 const char *stringStackLocal[kMAXSTRINGFOUND];
4134
4135 const bool willLoad = (instance==0 || fNeedLoading); fNeedLoading = false;
4136 if (willLoad) fDidBooleanOptimization = false;
4137
4138 Int_t pos = 0;
4139 Int_t pos2 = 0;
4140 for (Int_t i=0; i<fNoper ; ++i) {
4141
4142 const Int_t oper = GetOper()[i];
4143 const Int_t newaction = oper >> kTFOperShift;
4144
4146 // ROOT::v5::TFormula operands.
4147
4148 // one of the most used cases
4149 if (newaction==kConstant) { pos++; tab[pos-1] = GetConstant<T>(oper & kTFOperMask); continue; }
4150
4151 switch(newaction) {
4152
4153 case kEnd : return tab[0];
4154 case kAdd : pos--; tab[pos-1] += tab[pos]; continue;
4155 case kSubstract : pos--; tab[pos-1] -= tab[pos]; continue;
4156 case kMultiply : pos--; tab[pos-1] *= tab[pos]; continue;
4157 case kDivide : pos--; if (tab[pos] == 0) tab[pos-1] = 0; // division by 0
4158 else tab[pos-1] /= tab[pos];
4159 continue;
4160 case kModulo : {pos--;
4161 Long64_t int1((Long64_t)tab[pos-1]);
4162 Long64_t int2((Long64_t)tab[pos]);
4163 tab[pos-1] = T(int1 % int2);
4164 continue;}
4165
4166 case kcos : tab[pos-1] = TMath::Cos(tab[pos-1]); continue;
4167 case ksin : tab[pos-1] = TMath::Sin(tab[pos-1]); continue;
4168 case ktan : if (TMath::Cos(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
4169 else tab[pos-1] = TMath::Tan(tab[pos-1]);
4170 continue;
4171 case kacos : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
4172 else tab[pos-1] = TMath::ACos(tab[pos-1]);
4173 continue;
4174 case kasin : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
4175 else tab[pos-1] = TMath::ASin(tab[pos-1]);
4176 continue;
4177 case katan : tab[pos-1] = TMath::ATan(tab[pos-1]); continue;
4178 case kcosh : tab[pos-1] = TMath::CosH(tab[pos-1]); continue;
4179 case ksinh : tab[pos-1] = TMath::SinH(tab[pos-1]); continue;
4180 case ktanh : if (TMath::CosH(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
4181 else tab[pos-1] = TMath::TanH(tab[pos-1]);
4182 continue;
4183 case kacosh: if (tab[pos-1] < 1) {tab[pos-1] = 0;} // indetermination
4184 else tab[pos-1] = TMath::ACosH(tab[pos-1]);
4185 continue;
4186 case kasinh: tab[pos-1] = TMath::ASinH(tab[pos-1]); continue;
4187 case katanh: if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
4188 else tab[pos-1] = TMath::ATanH(tab[pos-1]);
4189 continue;
4190 case katan2: pos--; tab[pos-1] = TMath::ATan2(tab[pos-1],tab[pos]); continue;
4191
4192 case kfmod : pos--; tab[pos-1] = fmod_local(tab[pos-1],tab[pos]); continue;
4193 case kpow : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
4194 case ksq : tab[pos-1] = tab[pos-1]*tab[pos-1]; continue;
4195 case ksqrt : tab[pos-1] = TMath::Sqrt(TMath::Abs(tab[pos-1])); continue;
4196
4197 case kstrstr : pos2 -= 2; pos++;if (strstr(stringStack[pos2],stringStack[pos2+1])) tab[pos-1]=1;
4198 else tab[pos-1]=0;
4199 continue;
4200
4201 case kmin : pos--; tab[pos-1] = std::min(tab[pos-1],tab[pos]); continue;
4202 case kmax : pos--; tab[pos-1] = std::max(tab[pos-1],tab[pos]); continue;
4203
4204 case klog : if (tab[pos-1] > 0) tab[pos-1] = TMath::Log(tab[pos-1]);
4205 else {tab[pos-1] = 0;} //{indetermination }
4206 continue;
4207 case kexp : { Double_t dexp = tab[pos-1];
4208 if (dexp < -700) {tab[pos-1] = 0; continue;}
4209 if (dexp > 700) {tab[pos-1] = TMath::Exp(700); continue;}
4210 tab[pos-1] = TMath::Exp(dexp); continue;
4211 }
4212 case klog10: if (tab[pos-1] > 0) tab[pos-1] = TMath::Log10(tab[pos-1]);
4213 else {tab[pos-1] = 0;} //{indetermination }
4214 continue;
4215
4216 case kpi : pos++; tab[pos-1] = TMath::Pi(); continue;
4217
4218 case kabs : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
4219 case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1;
4220 continue;
4221 case kint : tab[pos-1] = T(Long64_t(tab[pos-1])); continue;
4222 case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
4223 case krndm : pos++; tab[pos-1] = gRandom->Rndm(); continue;
4224
4225 case kAnd : pos--; if (tab[pos-1]!=0 && tab[pos]!=0) tab[pos-1]=1;
4226 else tab[pos-1]=0;
4227 continue;
4228 case kOr : pos--; if (tab[pos-1]!=0 || tab[pos]!=0) tab[pos-1]=1;
4229 else tab[pos-1]=0;
4230 continue;
4231
4232 case kEqual : pos--; tab[pos-1] = (tab[pos-1] == tab[pos]) ? 1 : 0; continue;
4233 case kNotEqual : pos--; tab[pos-1] = (tab[pos-1] != tab[pos]) ? 1 : 0; continue;
4234 case kLess : pos--; tab[pos-1] = (tab[pos-1] < tab[pos]) ? 1 : 0; continue;
4235 case kGreater : pos--; tab[pos-1] = (tab[pos-1] > tab[pos]) ? 1 : 0; continue;
4236 case kLessThan : pos--; tab[pos-1] = (tab[pos-1] <= tab[pos]) ? 1 : 0; continue;
4237 case kGreaterThan: pos--; tab[pos-1] = (tab[pos-1] >= tab[pos]) ? 1 : 0; continue;
4238 case kNot : tab[pos-1] = (tab[pos-1] != 0) ? 0 : 1; continue;
4239
4240 case kStringEqual : pos2 -= 2; pos++; if (!strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
4241 else tab[pos-1]=0;
4242 continue;
4243 case kStringNotEqual: pos2 -= 2; pos++;if (strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
4244 else tab[pos-1]=0;
4245 continue;
4246
4247 case kBitAnd : pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) & ((ULong64_t) tab[pos]); continue;
4248 case kBitOr : pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) | ((ULong64_t) tab[pos]); continue;
4249 case kLeftShift : pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) <<((ULong64_t) tab[pos]); continue;
4250 case kRightShift: pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) >>((ULong64_t) tab[pos]); continue;
4251
4252 case kJump : i = (oper & kTFOperMask); continue;
4253 case kJumpIf : {
4254 pos--;
4255 if (!tab[pos]) {
4256 i = (oper & kTFOperMask);
4257 // If we skip the left (true) side of the if statement we may,
4258 // skip some of the branch loading (since we remove duplicate branch
4259 // request (in TTreeFormula constructor) and so we need to force the
4260 // loading here.
4262 }
4263 continue;
4264 }
4265
4266 case kStringConst: {
4267 // String
4268 pos2++; stringStack[pos2-1] = (char*)fExpr[i].Data();
4269 if (fAxis) {
4270 // See TT_EVAL_INIT
4271 Int_t bin = fAxis->FindBin(stringStack[pos2-1]);
4272 return bin;
4273 }
4274 continue;
4275 }
4276
4277 case kBoolOptimize: {
4278 // boolean operation optimizer
4279
4280 int param = (oper & kTFOperMask);
4281 bool skip = false;
4282 int op = param % 10; // 1 is && , 2 is ||
4283
4284 if (op == 1 && (!tab[pos-1]) ) {
4285 // &&: skip the right part if the left part is already false
4286
4287 skip = true;
4288
4289 // Preserve the existing behavior (i.e. the result of a&&b is
4290 // either 0 or 1)
4291 tab[pos-1] = 0;
4292
4293 } else if (op == 2 && tab[pos-1] ) {
4294 // ||: skip the right part if the left part is already true
4295
4296 skip = true;
4297
4298 // Preserve the existing behavior (i.e. the result of a||b is
4299 // either 0 or 1)
4300 tab[pos-1] = 1;
4301 }
4302
4303 if (skip) {
4304 int toskip = param / 10;
4305 i += toskip;
4307 }
4308 continue;
4309 }
4310
4311 case kFunctionCall: {
4312 // an external function call
4313
4314 int param = (oper & kTFOperMask);
4315 int fno = param / 1000;
4316 int nargs = param % 1000;
4317
4318 // Retrieve the function
4320
4321 // Set the arguments
4322 method->ResetParam();
4323 if (nargs) {
4324 UInt_t argloc = pos-nargs;
4325 for(Int_t j=0;j<nargs;j++,argloc++,pos--) {
4327 }
4328 }
4329 pos++;
4330 Double_t ret = 0;
4331 method->Execute(ret);
4332 tab[pos-1] = ret; // check for the correct conversion!
4333
4334 continue;
4335 }
4336
4337// case kParameter: { pos++; tab[pos-1] = fParams[(oper & kTFOperMask)]; continue; }
4338 }
4339
4340 } else {
4341 // TTreeFormula operands.
4342
4343 // a tree variable (the most used case).
4344
4345 if (newaction == kDefinedVariable) {
4346
4347 const Int_t code = (oper & kTFOperMask);
4348 const Int_t lookupType = fLookupType[code];
4349 switch (lookupType) {
4350 case kIndexOfEntry: tab[pos++] = (T)fTree->GetReadEntry(); continue;
4351 case kIndexOfLocalEntry: tab[pos++] = (T)fTree->GetTree()->GetReadEntry(); continue;
4352 case kEntries: tab[pos++] = (T)fTree->GetEntries(); continue;
4353 case kLocalEntries: tab[pos++] = (T)fTree->GetTree()->GetEntries(); continue;
4354 case kLength: tab[pos++] = fManager->fNdata; continue;
4355 case kLengthFunc: tab[pos++] = ((TTreeFormula*)fAliases.UncheckedAt(i))->GetNdata(); continue;
4356 case kIteration: tab[pos++] = instance; continue;
4357 case kSum: tab[pos++] = Summing<T>((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
4358 case kMin: tab[pos++] = FindMin<T>((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
4359 case kMax: tab[pos++] = FindMax<T>((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
4360
4361 case kDirect: { TT_EVAL_INIT_LOOP; tab[pos++] = leaf->GetTypedValue<T>(real_instance); continue; }
4362 case kMethod: { TT_EVAL_INIT_LOOP; tab[pos++] = GetValueFromMethod(code,leaf); continue; }
4364 GetTypedValue<T>(leaf,real_instance); continue; }
4366 GetTypedValue<T>((TLeaf*)nullptr,real_instance); continue; }
4367 case kEntryList: { TEntryList *elist = (TEntryList*)fExternalCuts.At(code);
4368 tab[pos++] = elist->Contains(fTree->GetReadEntry());
4369 continue;}
4370 case -1: break;
4371 default: tab[pos++] = 0; continue;
4372 }
4373 switch (fCodes[code]) {
4374 case -2: {
4375 TCutG *gcut = (TCutG*)fExternalCuts.At(code);
4376 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
4377 TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
4379 fx->ResetLoading();
4380 fy->ResetLoading();
4381 }
4382 T xcut = fx->EvalInstance<T>(instance);
4383 T ycut = fy->EvalInstance<T>(instance);
4384 tab[pos++] = gcut->IsInside(xcut,ycut);
4385 continue;
4386 }
4387 case -1: {
4388 TCutG *gcut = (TCutG*)fExternalCuts.At(code);
4389 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
4391 fx->ResetLoading();
4392 }
4393 tab[pos++] = fx->EvalInstance<T>(instance);
4394 continue;
4395 }
4396 default: {
4397 tab[pos++] = 0;
4398 continue;
4399 }
4400 }
4401 }
4402 switch(newaction) {
4403
4404 // a TTree Variable Alias (i.e. a sub-TTreeFormula)
4405 case kAlias: {
4406 int aliasN = i;
4409
4410 subform->fDidBooleanOptimization = fDidBooleanOptimization;
4411 T param = subform->EvalInstance<T>(instance);
4412
4413 tab[pos] = param; pos++;
4414 continue;
4415 }
4416 // a TTree Variable Alias String (i.e. a sub-TTreeFormula)
4417 case kAliasString: {
4418 int aliasN = i;
4421
4422 pos2++;
4423 subform->fDidBooleanOptimization = fDidBooleanOptimization;
4424 stringStack[pos2-1] = subform->EvalStringInstance(instance);
4425 continue;
4426 }
4427 case kMinIf: {
4428 int alternateN = i;
4430 TTreeFormula *condition = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN+1));
4431 T param = FindMin<T>(primary,condition);
4432 ++i; // skip the place holder for the condition
4433 tab[pos] = param; pos++;
4434 continue;
4435 }
4436 case kMaxIf: {
4437 int alternateN = i;
4439 TTreeFormula *condition = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN+1));
4440 T param = FindMax<T>(primary,condition);
4441 ++i; // skip the place holder for the condition
4442 tab[pos] = param; pos++;
4443 continue;
4444 }
4445
4446 // a TTree Variable Alternate (i.e. a sub-TTreeFormula)
4447 case kAlternate: {
4448 int alternateN = i;
4450
4451 // First check whether we are in range for the primary formula
4453
4454 T param = primary->EvalInstance<T>(instance);
4455
4456 ++i; // skip the alternate value.
4457
4458 tab[pos] = param; pos++;
4459 } else {
4460 // The primary is not in range, we will calculate the alternate value
4461 // via the next operation (which will be a intentional).
4462
4463 // kAlias no operations
4464 }
4465 continue;
4466 }
4467 case kAlternateString: {
4468 int alternateN = i;
4470
4471 // First check whether we are in range for the primary formula
4473
4474 pos2++;
4475 stringStack[pos2-1] = primary->EvalStringInstance(instance);
4476
4477 ++i; // skip the alternate value.
4478
4479 } else {
4480 // The primary is not in range, we will calculate the alternate value
4481 // via the next operation (which will be a kAlias).
4482
4483 // intentional no operations
4484 }
4485 continue;
4486 }
4487
4488 // a tree string
4489 case kDefinedString: {
4492
4493 // Now let calculate what physical instance we really need.
4495
4496 if (instance==0 || fNeedLoading) {
4497 fNeedLoading = false;
4498 TBranch *branch = leafc->GetBranch();
4499 Long64_t readentry = branch->GetTree()->GetReadEntry();
4501 } else {
4502 // In the cases where we are behind (i.e. right of) a potential boolean optimization
4503 // this tree variable reading may have not been executed with instance==0 which would
4504 // result in the branch being potentially not read in.
4506 TBranch *br = leafc->GetBranch();
4507 Long64_t treeEntry = br->GetTree()->GetReadEntry();
4509 }
4511 }
4512 pos2++;
4514 stringStack[pos2-1] = (char*)leafc->GetValuePointer();
4515 } else {
4517 }
4518 continue;
4519 }
4520
4521 }
4522 }
4523
4524 R__ASSERT(i<fNoper);
4525 }
4526
4527 //std::cout << __PRETTY_FUNCTION__ << " returning " << tab[0] << std::endl;
4528 return tab[0];
4529}
4530
4531// Template instantiations
4532template double TTreeFormula::EvalInstance<double> (int, char const**);
4533template long double TTreeFormula::EvalInstance<long double> (int, char const**);
4534template long long TTreeFormula::EvalInstance<long long> (int, char const**);
4535
4536////////////////////////////////////////////////////////////////////////////////
4537/// Return DataMember corresponding to code.
4538///
4539/// function called by TLeafObject::GetValue
4540/// with the value of fLookupType computed in TTreeFormula::DefinedVariable
4541
4543{
4544 return (TFormLeafInfo *)fDataMembers.UncheckedAt(code);
4546}
4547
4548////////////////////////////////////////////////////////////////////////////////
4549/// Return leaf corresponding to serial number n.
4550
4552{
4553 return (TLeaf*)fLeaves.UncheckedAt(n);
4554}
4555
4556////////////////////////////////////////////////////////////////////////////////
4557/// Return methodcall corresponding to code.
4558///
4559/// function called by TLeafObject::GetValue
4560/// with the value of fLookupType computed in TTreeFormula::DefinedVariable
4561
4563{
4564 return (TMethodCall *)fMethods.UncheckedAt(code);
4566}
4567
4568////////////////////////////////////////////////////////////////////////////////
4569/// Return number of available instances in the formula.
4570
4572{
4574}
4575
4576////////////////////////////////////////////////////////////////////////////////
4577/// Return result of a leafobject method.
4578
4580{
4582
4583 if (!m) {
4584 return 0.0;
4585 }
4586
4587 void* thisobj = nullptr;
4588 if (leaf->InheritsFrom(TLeafObject::Class())) {
4589 thisobj = ((TLeafObject*) leaf)->GetObject();
4590 } else {
4591 TBranchElement* branch = (TBranchElement*) ((TLeafElement*) leaf)->GetBranch();
4592 Int_t id = branch->GetID();
4593 // FIXME: This is wrong for a top-level branch.
4594 Int_t offset = 0;
4595 if (id > -1) {
4596 TStreamerInfo* info = branch->GetInfo();
4597 if (info) {
4598 offset = info->GetElementOffset(id);
4599 } else {
4600 Warning("GetValueFromMethod", "No streamer info for branch %s.", branch->GetName());
4601 }
4602 }
4603 if (id < 0) {
4604 char* address = branch->GetObject();
4605 thisobj = address;
4606 } else {
4607 //char* address = branch->GetAddress();
4608 char* address = branch->GetObject();
4609 if (address) {
4610 thisobj = *((char**) (address + offset));
4611 } else {
4612 // FIXME: If the address is not set, the object won't be either!
4613 thisobj = branch->GetObject();
4614 }
4615 }
4616 }
4617
4618 TMethodCall::EReturnType r = m->ReturnType();
4619
4620 if (r == TMethodCall::kLong) {
4621 Longptr_t l = 0;
4622 m->Execute(thisobj, l);
4623 return (Double_t) l;
4624 }
4625
4626 if (r == TMethodCall::kDouble) {
4627 Double_t d = 0.0;
4628 m->Execute(thisobj, d);
4629 return d;
4630 }
4631
4632 m->Execute(thisobj);
4633
4634 return 0;
4635}
4636
4637////////////////////////////////////////////////////////////////////////////////
4638/// Return result of a leafobject method.
4639
4641{
4643
4644 if (!m) {
4645 return nullptr;
4646 }
4647
4648 void* thisobj;
4649 if (leaf->InheritsFrom(TLeafObject::Class())) {
4650 thisobj = ((TLeafObject*) leaf)->GetObject();
4651 } else {
4652 TBranchElement* branch = (TBranchElement*) ((TLeafElement*) leaf)->GetBranch();
4653 Int_t id = branch->GetID();
4654 Int_t offset = 0;
4655 if (id > -1) {
4656 TStreamerInfo* info = branch->GetInfo();
4657 if (info) {
4658 offset = info->GetElementOffset(id);
4659 } else {
4660 Warning("GetValuePointerFromMethod", "No streamer info for branch %s.", branch->GetName());
4661 }
4662 }
4663 if (id < 0) {
4664 char* address = branch->GetObject();
4665 thisobj = address;
4666 } else {
4667 //char* address = branch->GetAddress();
4668 char* address = branch->GetObject();
4669 if (address) {
4670 thisobj = *((char**) (address + offset));
4671 } else {
4672 // FIXME: If the address is not set, the object won't be either!
4673 thisobj = branch->GetObject();
4674 }
4675 }
4676 }
4677
4678 TMethodCall::EReturnType r = m->ReturnType();
4679
4680 if (r == TMethodCall::kLong) {
4681 Longptr_t l = 0;
4682 m->Execute(thisobj, l);
4683 return nullptr;
4684 }
4685
4686 if (r == TMethodCall::kDouble) {
4687 Double_t d = 0.0;
4688 m->Execute(thisobj, d);
4689 return nullptr;
4690 }
4691
4692 if (r == TMethodCall::kOther) {
4693 char* c = nullptr;
4694 m->Execute(thisobj, &c);
4695 return c;
4696 }
4697
4698 m->Execute(thisobj);
4699
4700 return nullptr;
4701}
4702
4703////////////////////////////////////////////////////////////////////////////////
4704/// Return TRUE if the formula corresponds to one single Tree leaf
4705/// and this leaf is short, int or unsigned short, int
4706/// When a leaf is of type integer or string, the generated histogram is forced
4707/// to have an integer bin width
4708
4709bool TTreeFormula::IsInteger(bool fast) const
4710{
4711 if (fast) {
4712 if (TestBit(kIsInteger)) return true;
4713 else return false;
4714 }
4715
4716 if (fNoper==2 && GetAction(0)==kAlternate) {
4719 return subform->IsInteger(false);
4720 }
4721
4722 if (GetAction(0)==kMinIf || GetAction(0)==kMaxIf) {
4723 return false;
4724 }
4725
4726 if (fNoper > 1) return false;
4727
4728 if (GetAction(0)==kAlias) {
4731 return subform->IsInteger(false);
4732 }
4733
4734 if (fLeaves.GetEntries() != 1) {
4735 switch (fLookupType[0]) {
4736 case kIndexOfEntry:
4737 case kIndexOfLocalEntry:
4738 case kEntries:
4739 case kLocalEntries:
4740 case kLength:
4741 case kLengthFunc:
4742 case kIteration:
4743 return true;
4744 case kSum:
4745 case kMin:
4746 case kMax:
4747 case kEntryList:
4748 default:
4749 return false;
4750 }
4751 }
4752
4753 if (EvalClass()==TBits::Class()) return true;
4754
4755 if (IsLeafInteger(0) || IsLeafString(0)) return true;
4756 return false;
4757}
4759////////////////////////////////////////////////////////////////////////////////
4760/// Return TRUE if the leaf corresponding to code is short, int or unsigned
4761/// short, int When a leaf is of type integer, the generated histogram is
4762/// forced to have an integer bin width
4763
4764bool TTreeFormula::IsLeafInteger(Int_t code) const
4765{
4766 TLeaf *leaf = (TLeaf*)fLeaves.At(code);
4767 if (!leaf) {
4768 switch (fLookupType[code]) {
4769 case kIndexOfEntry:
4770 case kIndexOfLocalEntry:
4771 case kEntries:
4772 case kLocalEntries:
4773 case kLength:
4774 case kLengthFunc:
4775 case kIteration:
4776 return true;
4777 case kSum:
4778 case kMin:
4779 case kMax:
4780 case kEntryList:
4781 default:
4782 return false;
4783 }
4784 }
4785 if (fAxis) return true;
4787 switch (fLookupType[code]) {
4788 case kMethod:
4789 case kTreeMember:
4790 case kDataMember:
4791 info = GetLeafInfo(code);
4792 return info->IsInteger();
4793 case kDirect:
4794 break;
4795 }
4796 if (!strcmp(leaf->GetTypeName(),"Int_t")) return true;
4797 if (!strcmp(leaf->GetTypeName(),"Short_t")) return true;
4798 if (!strcmp(leaf->GetTypeName(),"UInt_t")) return true;
4799 if (!strcmp(leaf->GetTypeName(),"UShort_t")) return true;
4800 if (!strcmp(leaf->GetTypeName(),"Bool_t")) return true;
4801 if (!strcmp(leaf->GetTypeName(),"Char_t")) return true;
4802 if (!strcmp(leaf->GetTypeName(),"UChar_t")) return true;
4803 if (!strcmp(leaf->GetTypeName(),"Long64_t")) return true;
4804 if (!strcmp(leaf->GetTypeName(),"ULong64_t")) return true;
4805 if (!strcmp(leaf->GetTypeName(),"string")) return true;
4806 return false;
4807}
4808
4809////////////////////////////////////////////////////////////////////////////////
4810/// Return TRUE if the formula is a string
4811
4812bool TTreeFormula::IsString() const
4813{
4814 // See TTreeFormula::Init for the setting of kIsCharacter.
4815 return TestBit(kIsCharacter);
4817
4818////////////////////////////////////////////////////////////////////////////////
4819/// Return true if the expression at the index 'oper' is to be treated as
4820/// as string.
4821
4823{
4824 if (ROOT::v5::TFormula::IsString(oper)) return true;
4825 if (GetAction(oper)==kDefinedString) return true;
4826 if (GetAction(oper)==kAliasString) return true;
4827 if (GetAction(oper)==kAlternateString) return true;
4828 return false;
4829}
4830
4831////////////////////////////////////////////////////////////////////////////////
4832/// Return TRUE if the leaf or data member corresponding to code is a string
4833
4834bool TTreeFormula::IsLeafString(Int_t code) const
4835{
4836 TLeaf *leaf = (TLeaf*)fLeaves.At(code);
4838 if (fLookupType[code]==kTreeMember) {
4839 info = GetLeafInfo(code);
4840 return info->IsString();
4841 }
4842
4843 switch(fLookupType[code]) {
4844 case kDirect:
4845 if ( !leaf->IsUnsigned() && (leaf->InheritsFrom(TLeafC::Class()) || leaf->InheritsFrom(TLeafB::Class()) ) ) {
4846 // Need to find out if it is an 'array' or a pointer.
4847 if (leaf->GetLenStatic() > 1) return true;
4848
4849 // Now we need to differentiate between a variable length array and
4850 // a TClonesArray.
4851 if (leaf->GetLeafCount()) {
4852 const char* indexname = leaf->GetLeafCount()->GetName();
4853 if (indexname[strlen(indexname)-1] == '_' ) {
4854 // This in a clones array
4855 return false;
4856 } else {
4857 // this is a variable length char array
4858 return true;
4859 }
4860 }
4861 return false;
4862 } else if (leaf->InheritsFrom(TLeafElement::Class())) {
4863 TBranchElement * br = (TBranchElement*)leaf->GetBranch();
4864 Int_t bid = br->GetID();
4865 if (bid < 0) return false;
4866 if (br->GetInfo()==nullptr || !br->GetInfo()->IsCompiled()) {
4867 // Case where the file is corrupted is some ways.
4868 // We can not get to the actual type of the data
4869 // let's assume it is NOT a string.
4870 return false;
4871 }
4872 TStreamerElement * elem = (TStreamerElement*) br->GetInfo()->GetElement(bid);
4873 if (!elem) {
4874 // Case where the file is corrupted is some ways.
4875 // We can not get to the actual type of the data
4876 // let's assume it is NOT a string.
4877 return false;
4878 }
4879 if (elem->GetNewType() == TStreamerInfo::kOffsetL + TStreamerInfo::kChar) {
4880 // Check whether a specific element of the string is specified!
4881 if (fIndexes[code][fNdimensions[code]-1] != -1) return false;
4882 return true;
4883 }
4884 if ( elem->GetNewType() == TStreamerInfo::kCharStar) {
4885 // Check whether a specific element of the string is specified!
4886 if (fNdimensions[code] && fIndexes[code][fNdimensions[code]-1] != -1) return false;
4887 return true;
4888 }
4889 return false;
4890 } else {
4891 return false;
4892 }
4893 case kMethod:
4894 //TMethodCall *m = GetMethodCall(code);
4895 //TMethodCall::EReturnType r = m->ReturnType();
4896 return false;
4897 case kDataMember:
4898 info = GetLeafInfo(code);
4899 return info->IsString();
4900 default:
4901 return false;
4902 }
4903}
4904
4905////////////////////////////////////////////////////////////////////////////////
4906/// Return value of variable as a string
4907///
4908/// - mode = -2 : Print line with ***
4909/// - mode = -1 : Print column names
4910/// - mode = 0 : Print column values
4911
4913{
4914 return PrintValue(mode,0);
4915}
4916
4917////////////////////////////////////////////////////////////////////////////////
4918/// Return value of variable as a string
4919///
4920/// - mode = -2 : Print line with ***
4921/// - mode = -1 : Print column names
4922/// - mode = 0 : Print column values
4923///
4924/// decform contains the requested format (with the same convention as printf).
4925
4926char *TTreeFormula::PrintValue(Int_t mode, Int_t instance, const char *decform) const
4927{
4928 const int kMAXLENGTH = kMaxLen;
4929 static char value[kMAXLENGTH];
4930
4931 if (mode == -2) {
4932 for (int i = 0; i < kMAXLENGTH-1; i++)
4933 value[i] = '*';
4934 value[kMAXLENGTH-1] = 0;
4935 } else if (mode == -1) {
4936 snprintf(value, kMAXLENGTH-1, "%s", GetTitle());
4937 } else if (mode == 0) {
4938 if ( (fNstring && fNval==0 && fNoper==1) || IsString() )
4939 {
4940 const char * val = nullptr;
4941 if (GetAction(0)==kStringConst) {
4942 val = fExpr[0].Data();
4943 } else if (instance<fNdata[0]) {
4944 if (fNoper == 1) {
4945 if (fLookupType[0]==kTreeMember) {
4946 val = (char*)GetLeafInfo(0)->GetValuePointer((TLeaf*)nullptr,instance);
4947 } else {
4949 TBranch *branch = leaf->GetBranch();
4950 Long64_t readentry = branch->GetTree()->GetReadEntry();
4952 if (fLookupType[0]==kDirect && fNoper==1) {
4953 val = (const char*)leaf->GetValuePointer();
4954 } else {
4955 val = ((TTreeFormula*)this)->EvalStringInstance(instance);
4956 }
4957 }
4958 } else {
4959 val = ((TTreeFormula*)this)->EvalStringInstance(instance);
4960 }
4961 }
4962 if (val) {
4963 strlcpy(value, val, kMAXLENGTH);
4964 } else {
4965 value[0] = '\0';
4966 }
4967 value[kMAXLENGTH-1] = 0;
4968 } else {
4969 //NOTE: This is terrible form ... but is forced upon us by the fact that we can not
4970 //use the mutable keyword AND we should keep PrintValue const.
4971 Int_t real_instance = ((TTreeFormula*)this)->GetRealInstance(instance,-1);
4972 if (real_instance<fNdata[0]) {
4975 char *expo = nullptr;
4976 if (len>2) {
4977 switch (decform[len-2]) {
4978 case 'l':
4979 case 'L': {
4980 outputSizeLevel = 2;
4981 if (len>3 && tolower(decform[len-3])=='l') {
4982 outputSizeLevel = 3;
4983 }
4984 break;
4985 }
4986 case 'h': outputSizeLevel = 0; break;
4987 }
4988 }
4989 switch(decform[len-1]) {
4990 case 'c':
4991 case 'd':
4992 case 'i':
4993 {
4994 switch (outputSizeLevel) {
4995 case 0: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Short_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4996 case 2: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Long_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4998 case 1:
4999 default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Int_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
5000 }
5001 break;
5002 }
5003 case 'o':
5004 case 'x':
5005 case 'X':
5006 case 'u':
5007 {
5008 switch (outputSizeLevel) {
5009 case 0: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(UShort_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
5010 case 2: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(ULong_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
5012 case 1:
5013 default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(UInt_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
5014 }
5015 break;
5016 }
5017 case 'f':
5018 case 'e':
5019 case 'E':
5020 case 'g':
5021 case 'G':
5022 {
5023 switch (outputSizeLevel) {
5025 case 1:
5026 default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),((TTreeFormula*)this)->EvalInstance(instance)); break;
5027 }
5028 expo = strchr(value,'e');
5029 break;
5030 }
5031 default:
5033 expo = strchr(value,'e');
5034 }
5035 if (expo) {
5036 // If there is an exponent we may be longer than planned.
5037 // so let's trim off the excess precision!
5038 UInt_t declen = atoi(decform);
5039 if (strlen(value)>declen) {
5040 UInt_t off = strlen(value)-declen;
5041 char *start = expo - off;
5043 for(UInt_t z=0;z<=vlen;++z) {
5044 start[z] = expo[z];
5045 }
5046 //strcpy(expo-off,expo);
5047 }
5048 }
5049 } else {
5050 if (isalpha(decform[strlen(decform)-1])) {
5052 short_decform.Remove(short_decform.Length()-1);
5053 snprintf(value,kMAXLENGTH,Form(" %%%sc",short_decform.Data()),' ');
5054 } else {
5055 snprintf(value,kMAXLENGTH,Form(" %%%sc",decform),' ');
5056 }
5057
5058 }
5059 }
5060 }
5061 return &value[0];
5062}
5063
5064////////////////////////////////////////////////////////////////////////////////
5065/// Tell the formula that we are going to request a new entry.
5066
5068{
5069 fNeedLoading = true;
5071
5072 for(Int_t i=0; i<fNcodes; ++i) {
5073 UInt_t max_dim = fNdimensions[i];
5074 for(UInt_t dim=0; dim<max_dim ;++dim) {
5075 if (fVarIndexes[i][dim]) {
5076 fVarIndexes[i][dim]->ResetLoading();
5077 }
5078 }
5079 }
5080 Int_t n = fAliases.GetLast();
5081 if ( fNoper < n ) {
5082 n = fNoper;
5083 }
5084 for(Int_t k=0; k <= n; ++k) {
5085 TTreeFormula *f = static_cast<TTreeFormula*>(fAliases.UncheckedAt(k));
5086 if (f) {
5087 f->ResetLoading();
5088 }
5089 }
5090 for (int i=0; i<fExternalCuts.GetSize(); i++) {
5091 auto c = dynamic_cast<TCutG*>(fExternalCuts.At(i));
5092 if (c) {
5093 ((TTreeFormula *)(c->GetObjectX()))->ResetLoading();
5094 ((TTreeFormula *)(c->GetObjectY()))->ResetLoading();
5095 }
5096 }
5100}
5101
5102////////////////////////////////////////////////////////////////////////////////
5103/// Set the axis (in particular get the type).
5104
5105void TTreeFormula::SetAxis(TAxis *axis)
5106{
5107 if (!axis) {fAxis = nullptr; return;}
5108 if (IsString()) {
5109 fAxis = axis;
5110 if (fNoper==1 && GetAction(0)==kAliasString){
5113 subform->SetAxis(axis);
5114 } else if (fNoper==2 && GetAction(0)==kAlternateString){
5117 subform->SetAxis(axis);
5118 }
5119 // Since the bin are corresponding to 'string', we currently must also set
5120 // the axis to align the bins exactly on integer boundaries.
5122 } else if (IsInteger()) {
5125}
5126
5127////////////////////////////////////////////////////////////////////////////////
5128/// Stream an object of class TTreeFormula.
5129
5131{
5132 if (R__b.IsReading()) {
5133 UInt_t R__s, R__c;
5134 Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
5135 if (R__v > 2) {
5136 R__b.ReadClassBuffer(TTreeFormula::Class(), this, R__v, R__s, R__c);
5137 return;
5138 }
5139 //====process old versions before automatic schema evolution
5141 R__b >> fTree;
5142 R__b >> fNcodes;
5143 R__b.ReadFastArray(fCodes, fNcodes);
5146 R__b >> instance; //data member removed
5147 R__b >> fNindex;
5148 if (fNindex) {
5149 fLookupType = new Int_t[fNindex];
5150 R__b.ReadFastArray(fLookupType, fNindex);
5151 }
5153 //====end of old versions
5154
5155 } else {
5156 R__b.WriteClassBuffer(TTreeFormula::Class(),this);
5157 }
5159
5160////////////////////////////////////////////////////////////////////////////////
5161/// Try to 'demote' a string into an array bytes. If this is not possible,
5162/// return false.
5163
5165{
5166 Int_t code = GetActionParam(oper);
5168 if (oper>0 && GetAction(oper-1)==kJump) {
5169 // We are the second hand of a ternary operator, let's not do the fixing.
5170 return false;
5171 }
5172 TLeaf *leaf = (TLeaf*)fLeaves.At(code);
5173 if (leaf && (leaf->InheritsFrom(TLeafC::Class()) || leaf->InheritsFrom(TLeafB::Class()) ) ) {
5175 fNval++;
5176 fNstring--;
5177 return true;
5178 }
5179 }
5180 return false;
5181}
5182
5183
5184////////////////////////////////////////////////////////////////////////////////
5185/// This function is called TTreePlayer::UpdateFormulaLeaves, itself
5186/// called by TChain::LoadTree when a new Tree is loaded.
5187/// Because Trees in a TChain may have a different list of leaves, one
5188/// must update the leaves numbers in the TTreeFormula used by the TreePlayer.
5189///
5190/// A safer alternative would be to recompile the whole thing .... However
5191/// currently compile HAS TO be called from the constructor!
5192
5194{
5197 for (Int_t i=0;i<nleaves;i++) {
5198 if (!fTree) break;
5199 if (!fLeafNames[i]) continue;
5200
5202 fLeaves[i] = leaf;
5203 if (fBranches[i] && leaf) {
5204 fBranches[i] = leaf->GetBranch();
5205 // Since sometimes we might no read all the branches for all the entries, we
5206 // might sometimes only read the branch count and thus reset the collection
5207 // but might not read the data branches, to insure that a subsequent read
5208 // from TTreeFormula will properly load the data branches even if fQuickLoad is true,
5209 // we reset the entry of all branches in the TTree.
5210 ((TBranch*)fBranches[i])->ResetReadEntry();
5211 }
5212 if (leaf==nullptr) SetBit( kMissingLeaf );
5213 }
5214 for (Int_t j=0; j<kMAXCODES; j++) {
5215 for (Int_t k = 0; k<kMAXFORMDIM; k++) {
5216 if (fVarIndexes[j][k]) {
5218 }
5219 }
5221 if (j<fNval && fCodes[j]<0) {
5223 if (gcut) {
5224 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
5225 TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
5226 if (fx) fx->UpdateFormulaLeaves();
5227 if (fy) fy->UpdateFormulaLeaves();
5228 }
5229 }
5230 }
5231 for(Int_t k=0;k<fNoper;k++) {
5232 const Int_t oper = GetOper()[k];
5233 switch(oper >> kTFOperShift) {
5234 case kAlias:
5235 case kAliasString:
5236 case kAlternate:
5237 case kAlternateString:
5238 case kMinIf:
5239 case kMaxIf:
5240 {
5243 subform->UpdateFormulaLeaves();
5244 break;
5245 }
5246 case kDefinedVariable:
5247 {
5248 Int_t code = GetActionParam(k);
5249 if (fCodes[code]==0) switch(fLookupType[code]) {
5250 case kLengthFunc:
5251 case kSum:
5252 case kMin:
5253 case kMax:
5254 {
5257 subform->UpdateFormulaLeaves();
5258 break;
5259 }
5260 default:
5261 break;
5262 }
5263 }
5264 default:
5265 break;
5266 }
5268}
5269
5270////////////////////////////////////////////////////////////////////////////////
5271/// Populate the TTreeFormulaManager with the dimension information.
5272
5274 Int_t i,k;
5275
5276 // Now that we saw all the expressions and variables AND that
5277 // we know whether arrays of chars are treated as string or
5278 // not, we can properly setup the dimensions.
5279 TIter next(fDimensionSetup);
5280 Int_t last_code = -1;
5281 Int_t virt_dim = 0;
5282 for(TDimensionInfo * info; (info = (TDimensionInfo*)next()); ) {
5283 if (last_code!=info->fCode) {
5284 // We know that the list is ordered by code number then by
5285 // dimension. Thus a different code means that we need to
5286 // restart at the lowest dimensions.
5287 virt_dim = 0;
5288 last_code = info->fCode;
5290 }
5291
5292 if (GetAction(info->fOper)==kDefinedString) {
5293
5294 // We have a string used as a string (and not an array of number)
5295 // We need to determine which is the last dimension and skip it.
5297 while(nextinfo && nextinfo->fCode==info->fCode) {
5298 DefineDimensions(info->fCode,info->fSize, info->fMultiDim, virt_dim);
5299 nextinfo = (TDimensionInfo*)next();
5300 }
5301 if (!nextinfo) break;
5302
5303 info = nextinfo;
5304 virt_dim = 0;
5305 last_code = info->fCode;
5307
5308 info->fSize = 1; // Maybe this should actually do nothing!
5309 }
5310
5311
5312 DefineDimensions(info->fCode,info->fSize, info->fMultiDim, virt_dim);
5313 }
5314
5315 fMultiplicity = 0;
5316 for(i=0;i<fNoper;i++) {
5317 Int_t action = GetAction(i);
5318
5319 if (action==kMinIf || action==kMaxIf) {
5320 // Skip/Ignore the 2nd args
5321 ++i;
5322 continue;
5323 }
5324 if (action==kAlias || action==kAliasString) {
5327 switch(subform->GetMultiplicity()) {
5328 case 0: break;
5329 case 1: fMultiplicity = 1; break;
5330 case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
5331 }
5333 // since we are addint to this manager 'subform->ResetDimensions();'
5334 // will be called a little latter
5335 continue;
5336 }
5337 if (action==kDefinedString) {
5338 //if (fOper[i] >= 105000 && fOper[i]<110000) {
5339 // We have a string used as a string
5340
5341 // This dormant portion of code would be used if (when?) we allow the histogramming
5342 // of the integral content (as opposed to the string content) of strings
5343 // held in a variable size container delimited by a null (as opposed to
5344 // a fixed size container or variable size container whose size is controlled
5345 // by a variable). In GetNdata, we will then use strlen to grab the current length.
5346 //fCumulSizes[i][fNdimensions[i]-1] = 1;
5347 //fUsedSizes[fNdimensions[i]-1] = -TMath::Abs(fUsedSizes[fNdimensions[i]-1]);
5348 //fUsedSizes[0] = - TMath::Abs( fUsedSizes[0]);
5349
5350 //continue;
5351 }
5352 }
5353
5354 for (i=0;i<fNcodes;i++) {
5355 if (fCodes[i] < 0) {
5357 if (!gcut) continue;
5358 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
5359 TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
5360
5361 if (fx) {
5362 switch(fx->GetMultiplicity()) {
5363 case 0: break;
5364 case 1: fMultiplicity = 1; break;
5365 case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
5366 }
5367 fManager->Add(fx);
5368 }
5369 if (fy) {
5370 switch(fy->GetMultiplicity()) {
5371 case 0: break;
5372 case 1: fMultiplicity = 1; break;
5373 case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
5374 }
5375 fManager->Add(fy);
5376 }
5377
5378 continue;
5379 }
5380
5381 if (fLookupType[i]==kIteration) {
5382 fMultiplicity = 1;
5383 continue;
5384 }
5385
5386 TLeaf *leaf = i <= fLeaves.GetLast() ? (TLeaf*)fLeaves.UncheckedAt(i) : nullptr;
5387 if (!leaf) continue;
5388
5389 // Reminder of the meaning of fMultiplicity:
5390 // -1: Only one or 0 element per entry but contains variable length
5391 // -array! (Only used for TTreeFormulaManager)
5392 // 0: Only one element per entry, no variable length array
5393 // 1: loop over the elements of a variable length array
5394 // 2: loop over elements of fixed length array (nData is the same for all entry)
5395
5396 if (leaf->GetLeafCount()) {
5397 // We assume only one possible variable length dimension (the left most)
5398 fMultiplicity = 1;
5399 } else if (fLookupType[i]==kDataMember) {
5401 TStreamerElement * elem = leafinfo->fElement;
5402 if (fMultiplicity!=1) {
5403 if (leafinfo->HasCounter() ) fMultiplicity = 1;
5404 else if (elem && elem->GetArrayDim()>0) fMultiplicity = 2;
5405 else if (leaf->GetLenStatic()>1) fMultiplicity = 2;
5406 }
5407 } else {
5408 if (leaf->GetLenStatic()>1 && fMultiplicity!=1) fMultiplicity = 2;
5409 }
5410 if (fMultiplicity!=1) {
5411 // If the leaf belongs to a friend tree which has an index, we might
5412 // be in the case where some entry do not exist.
5413
5414 TTree *realtree = fTree ? fTree->GetTree() : nullptr;
5415 TTree *tleaf = leaf->GetBranch()->GetTree();
5416 if (tleaf && tleaf != realtree && tleaf->GetTreeIndex()) {
5417 // Reset the multiplicity if we have a friend tree with an index.
5418 fMultiplicity = 1;
5419 }
5420 }
5421
5422 Int_t virt_dim2 = 0;
5423 for (k = 0; k < fNdimensions[i]; k++) {
5424 // At this point fCumulSizes[i][k] actually contain the physical
5425 // dimension of the k-th dimensions.
5426 if ( (fCumulSizes[i][k]>=0) && (fIndexes[i][k] >= fCumulSizes[i][k]) ) {
5427 // unreachable element requested:
5428 fManager->CancelDimension(virt_dim2); // fCumulUsedSizes[virt_dim2] = 0;
5429 }
5430 if ( fIndexes[i][k] < 0 ) virt_dim2++;
5431 fFixedSizes[i][k] = fCumulSizes[i][k];
5432 }
5433
5434 // Add up the cumulative size
5435 for (k = fNdimensions[i] - 1; (k > 0); k--) {
5436 // NOTE: When support for inside variable dimension is added this
5437 // will become inaccurate (since one of the value in the middle of the chain
5438 // is unknown until GetNdata is called.
5439 fCumulSizes[i][k-1] *= TMath::Abs(fCumulSizes[i][k]);
5440 }
5441 // NOTE: We assume that the inside variable dimensions are dictated by the
5442 // first index.
5443 if (fCumulSizes[i][0]>0) fNdata[i] = fCumulSizes[i][0];
5444
5445 //for (k = 0; k<kMAXFORMDIM; k++) {
5446 // if (fVarIndexes[i][k]) fManager->Add(fVarIndexes[i][k]);
5447 //}
5448
5450}
5451
5452////////////////////////////////////////////////////////////////////////////////
5453/// Make sure that all the branches have been loaded properly.
5454
5456{
5457 Int_t i;
5458 for (i=0; i<fNoper ; ++i) {
5460 if (leaf==nullptr) continue;
5461
5462 TBranch *br = leaf->GetBranch();
5463 Long64_t treeEntry = br->GetTree()->GetReadEntry();
5465
5467 if (alias) alias->LoadBranches();
5468
5469 Int_t max_dim = fNdimensions[i];
5470 for (Int_t dim = 0; dim < max_dim; ++dim) {
5471 if (fVarIndexes[i][dim]) fVarIndexes[i][dim]->LoadBranches();
5472 }
5474}
5475
5476////////////////////////////////////////////////////////////////////////////////
5477/// Calculate the actual dimension for the current entry.
5478
5480 Int_t size;
5481 bool outofbounds = false;
5482
5483 for (Int_t i=0;i<fNcodes;i++) {
5484 if (fCodes[i] < 0) continue;
5485
5486 // NOTE: Currently only the leafcount can indicate a dimension that
5487 // is physically variable. So only the left-most dimension is variable.
5488 // When an API is introduced to be able to determine a variable inside dimensions
5489 // one would need to add a way to recalculate the values of fCumulSizes for this
5490 // leaf. This would probably require the addition of a new data member
5491 // fSizes[kMAXCODES][kMAXFORMDIM];
5492 // Also note that EvalInstance expect all the values (but the very first one)
5493 // of fCumulSizes to be positive. So indicating that a physical dimension is
5494 // variable (expected for the first one) can NOT be done via negative values of
5495 // fCumulSizes.
5496
5497 TLeaf *leaf = i <= fLeaves.GetLast() ? (TLeaf *)fLeaves.UncheckedAt(i) : nullptr;
5498 if (!leaf) {
5499 switch(fLookupType[i]) {
5500 case kDirect:
5501 case kMethod:
5502 case kTreeMember:
5503 case kDataMember:
5504 fNdata[i] = 0;
5505 outofbounds = true;
5506 }
5507 continue;
5508 }
5509
5511 TTree *tleaf = leaf->GetBranch()->GetTree();
5512 if (tleaf && tleaf != realtree && tleaf->GetTreeIndex()) {
5513 if (tleaf->GetReadEntry() < 0) {
5514 fNdata[i] = 0;
5515 outofbounds = true;
5516 continue;
5517 } else {
5518 fNdata[i] = fCumulSizes[i][0];
5519 }
5520 }
5521 bool hasBranchCount2 = false;
5522 if (leaf->GetLeafCount()) {
5523 TLeaf* leafcount = leaf->GetLeafCount();
5524 TBranch *branchcount = leafcount->GetBranch();
5525 TFormLeafInfo * info = nullptr;
5526 if (leaf->IsA() == TLeafElement::Class()) {
5527 //if branchcount address not yet set, GetEntry will set the address
5528 // read branchcount value
5529 Long64_t readentry = leaf->GetBranch()->GetTree()->GetReadEntry();
5530 if (readentry < 0) readentry=0;
5531 if (!branchcount->GetAddress()) {
5533 } else {
5534 // Since we do not read the full branch let's reset the read entry number
5535 // so that a subsequent read from TTreeFormula will properly load the full
5536 // object even if fQuickLoad is true.
5537 branchcount->TBranch::GetEntry(readentry);
5538 branchcount->ResetReadEntry();
5539 }
5540
5541 size = ((TBranchElement*)branchcount)->GetNdata();
5542 // Reading the size as above is correct only when the branchcount
5543 // is of streamer type kCounter which require the underlying data
5544 // member to be signed integral type.
5545
5546 TBranchElement* branch = (TBranchElement*) leaf->GetBranch();
5547 if (branch->GetAddress() == nullptr) {
5548 // Humm there is no space reserve to write the data,
5549 // the data member is likely 'removed' from the class
5550 // layout, so rather than crashing by accessing
5551 // random memory, make it clear we can't read it.
5552 size = 0;
5553 }
5554
5555 // NOTE: could be sped up
5556 if (fHasMultipleVarDim[i]) {// info && info->GetVarDim()>=0) {
5558 if (branch->GetBranchCount2()) R__LoadBranch(branch->GetBranchCount2(),readentry,fQuickLoad);
5560
5561 // Here we need to add the code to take in consideration the
5562 // double variable length
5563 // We fill up the array of sizes in the TLeafInfo:
5564 info->LoadSizes(branch);
5565 hasBranchCount2 = true;
5566 if (info->GetVirtVarDim()>=0) info->UpdateSizes(fManager->fVarDims[info->GetVirtVarDim()]);
5567
5568 // Refresh the fCumulSizes[i] to have '1' for the
5569 // double variable dimensions
5570 Int_t vdim = info->GetVarDim();
5571 fCumulSizes[i][vdim] = fCumulSizes[i][vdim+1];
5572 for(Int_t k=vdim -1; k>=0; k--) {
5573 fCumulSizes[i][k] = fCumulSizes[i][k+1]*fFixedSizes[i][k];
5574 }
5575 // Update fCumulUsedSizes
5576 // UpdateMultiVarSizes(vdim,info,i)
5577 //Int_t fixed = fCumulSizes[i][vdim+1];
5578 //for(Int_t k=vdim - 1; k>=0; k++) {
5579 // Int_t fixed *= fFixedSizes[i][k];
5580 // for(Int_t l=0;l<size; l++) {
5581 // fCumulSizes[i][k] += info->GetSize(l) * fixed;
5582 //}
5583 }
5584 } else {
5585 Long64_t readentry = leaf->GetBranch()->GetTree()->GetReadEntry();
5586 if (readentry < 0) readentry=0;
5588 size = leaf->GetLen() / leaf->GetLenStatic();
5589 }
5590 if (hasBranchCount2) {
5591 // We assume that fCumulSizes[i][1] contains the product of the fixed sizes
5592 fNdata[i] = fCumulSizes[i][1] * ((TFormLeafInfo *)fDataMembers.At(i))->GetSumOfSizes();
5593 } else {
5594 fNdata[i] = size * fCumulSizes[i][1];
5595 }
5596 if (fIndexes[i][0]==-1) {
5597 // Case where the index is not specified AND the 1st dimension has a variable
5598 // size.
5599 if (fManager->fUsedSizes[0]==1 || (size<fManager->fUsedSizes[0]) ) fManager->fUsedSizes[0] = size;
5600 if (info && fIndexes[i][info->GetVarDim()]>=0) {
5601 for(Int_t j=0; j<size; j++) {
5602 if (fIndexes[i][info->GetVarDim()] >= info->GetSize(j)) {
5603 info->SetSize(j,0);
5606 } else if (fIndexes[i][info->GetVarDim()]>=0) {
5607 // There is an index and it is not too large
5608 info->SetSize(j,1);
5611 }
5612 }
5613 }
5614 } else if (fIndexes[i][0] >= size) {
5615 // unreachable element requested:
5616 fManager->fUsedSizes[0] = 0;
5617 fNdata[i] = 0;
5618 outofbounds = true;
5619 } else if (hasBranchCount2) {
5622 if (fIndexes[i][0]<0
5623 || fIndexes[i][info2->GetVarDim()] >= info2->GetSize(fIndexes[i][0])) {
5624 // unreachable element requested:
5625 fManager->fUsedSizes[0] = 0;
5626 fNdata[i] = 0;
5627 outofbounds = true;
5628 }
5629 }
5630 } else if (fLookupType[i]==kDataMember) {
5632 if (leafinfo->HasCounter()) {
5633 TBranch *branch = leaf->GetBranch();
5634 Long64_t readentry = branch->GetTree()->GetReadEntry();
5635 if (readentry < 0) readentry=0;
5637 size = (Int_t) leafinfo->GetCounterValue(leaf);
5638 if (fIndexes[i][0]==-1) {
5639 // Case where the index is not specified AND the 1st dimension has a variable
5640 // size.
5641 if (fManager->fUsedSizes[0]==1 || (size<fManager->fUsedSizes[0]) ) {
5642 fManager->fUsedSizes[0] = size;
5643 }
5644 } else if (fIndexes[i][0] >= size) {
5645 // unreachable element requested:
5646 fManager->fUsedSizes[0] = 0;
5647 fNdata[i] = 0;
5648 outofbounds = true;
5649 } else {
5650 fNdata[i] = size*fCumulSizes[i][1];
5651 }
5652 Int_t vdim = leafinfo->GetVarDim();
5653 if (vdim>=0) {
5654 // Here we need to add the code to take in consideration the
5655 // double variable length
5656 // We fill up the array of sizes in the TLeafInfo:
5657 // here we can assume that branch is a TBranch element because the other style does NOT support this type
5658 // of complexity.
5659 leafinfo->LoadSizes(branch);
5660 hasBranchCount2 = true;
5661 if (fIndexes[i][0]==-1&&fIndexes[i][vdim] >= 0) {
5662 for(int z=0; z<size; ++z) {
5663 if (fIndexes[i][vdim] >= leafinfo->GetSize(z)) {
5664 leafinfo->SetSize(z,0);
5665 // --fManager->fUsedSizes[0];
5666 } else if (fIndexes[i][vdim] >= 0 ) {
5667 leafinfo->SetSize(z,1);
5668 }
5669 }
5670 }
5671 leafinfo->UpdateSizes(fManager->fVarDims[vdim]);
5672
5673 // Refresh the fCumulSizes[i] to have '1' for the
5674 // double variable dimensions
5675 fCumulSizes[i][vdim] = fCumulSizes[i][vdim+1];
5676 for(Int_t k=vdim -1; k>=0; k--) {
5677 fCumulSizes[i][k] = fCumulSizes[i][k+1]*fFixedSizes[i][k];
5678 }
5679 fNdata[i] = fCumulSizes[i][1] * leafinfo->GetSumOfSizes();
5680 } else {
5681 fNdata[i] = size * fCumulSizes[i][1];
5682 }
5683 } else if (leafinfo->GetMultiplicity()==-1) {
5684 TBranch *branch = leaf->GetBranch();
5685 Long64_t readentry = branch->GetTree()->GetReadEntry();
5686 if (readentry < 0) readentry=0;
5688 if (leafinfo->GetNdata(leaf)==0) {
5689 outofbounds = true;
5690 }
5691 }
5692 }
5693 // However we allow several dimensions that virtually vary via the size of their
5694 // index variables. So we have code to recalculate fCumulUsedSizes.
5695 TFormLeafInfo * info = nullptr;
5696 if (fLookupType[i]!=kDirect) {
5698 }
5699 for(Int_t k=0, virt_dim=0; k < fNdimensions[i]; k++) {
5700 if (fIndexes[i][k]<0) {
5701 if (info && fIndexes[i][k]==-2 && fVarIndexes[i][k]->GetManager()->GetMultiplicity()==0) {
5702 // Index and thus local size provided by a "index variable of size 1"
5703 Int_t index = fVarIndexes[i][k]->EvalInstance(0);
5704 Int_t index_size = info->GetSize(index);
5705 if (fManager->fUsedSizes[virt_dim]==1 || (index_size!=1 && index_size<fManager->fUsedSizes[virt_dim]) )
5707 } else if (fIndexes[i][k]==-2 && fManager->fVirtUsedSizes[virt_dim]<0) {
5708
5709 // if fVirtUsedSize[virt_dim] is positive then VarIndexes[i][k]->GetNdata()
5710 // is always the same and has already been factored in fUsedSize[virt_dim]
5712 if (index_size==1) {
5713 // We could either have a variable size array which is currently of size one
5714 // or a single element that might or not might not be present (and is currently present!)
5715 if (fVarIndexes[i][k]->GetManager()->GetMultiplicity()==1) {
5717 }
5718
5720 index_size<fManager->fUsedSizes[virt_dim]) {
5722 }
5723
5724 } else if (hasBranchCount2 && info && k==info->GetVarDim()) {
5725 // NOTE: We assume the indexing of variable sizes on the first index!
5726 if (fIndexes[i][0]>=0) {
5727 Int_t index_size = info->GetSize(fIndexes[i][0]);
5728 if (fManager->fUsedSizes[virt_dim]==1 || (index_size!=1 && index_size<fManager->fUsedSizes[virt_dim]) )
5730 }
5731 }
5732 virt_dim++;
5733 } else if (hasBranchCount2 && info && k==info->GetVarDim()) {
5734
5735 // nothing to do, at some point I thought this might be useful:
5736 // if (fIndexes[i][k]>=0) {
5737 // index = info->GetSize(fIndexes[i][k]);
5738 // if (fManager->fUsedSizes[virt_dim]==1 || (index!=1 && index<fManager->fUsedSizes[virt_dim]) )
5739 // fManager->fUsedSizes[virt_dim] = index;
5740 // virt_dim++;
5741 // }
5742
5743 }
5744 }
5745 }
5746 return ! outofbounds;
5747
5748
5749
5750}
5751
5753{
5754 // Convert the fOper of a TTTreeFormula version fromVersion to the current in memory version
5755
5756 enum { kOldAlias = /*ROOT::v5::TFormula::kVariable*/ 100000+10000+1,
5760 };
5761
5762 for (int k=0; k<fNoper; k++) {
5763 // First hide from ROOT::v5::TFormula convertion
5764
5765 Int_t action = GetOper()[k];
5766
5767 switch (action) {
5768
5769 case kOldAlias: GetOper()[k] = -kOldAlias; break;
5770 case kOldAliasString: GetOper()[k] = -kOldAliasString; break;
5771 case kOldAlternate: GetOper()[k] = -kOldAlternate; break;
5772 case kOldAlternateString: GetOper()[k] = -kOldAlternateString; break;
5773 }
5774 }
5775
5777
5778 for (int i=0,offset=0; i<fNoper; i++) {
5779 Int_t action = GetOper()[i+offset];
5780
5781 switch (action) {
5782 case -kOldAlias: SetAction(i, kAlias, 0); break;
5783 case -kOldAliasString: SetAction(i, kAliasString, 0); break;
5784 case -kOldAlternate: SetAction(i, kAlternate, 0); break;
5785 case -kOldAlternateString: SetAction(i, kAlternateString, 0); break;
5786 }
5787 }
5788
5789}
5790
5791////////////////////////////////////////////////////////////////////////////////
5792/// Convert the underlying lookup method from the direct technique
5793/// (dereferencing the address held by the branch) to the method using
5794/// TFormLeafInfo. This is in particular useful in the case where we
5795/// need to append an additional TFormLeafInfo (for example to call a
5796/// method).
5797/// Return false if the switch was unsuccessful (basically in the
5798/// case of an old style split tree).
5799
5801{
5802 TFormLeafInfo *last = nullptr;
5803 TLeaf *leaf = (TLeaf*)fLeaves.At(code);
5804 if (!leaf) return false;
5805
5806 if (fLookupType[code]==kDirect) {
5807 if (leaf->InheritsFrom(TLeafElement::Class())) {
5808 TBranchElement * br = (TBranchElement*)leaf->GetBranch();
5809 if (br->GetType()==31) {
5810 // sub branch of a TClonesArray
5811 TStreamerInfo *info = br->GetInfo();
5812 TClass* cl = info->GetClass();
5813 TStreamerElement *element = (TStreamerElement *)info->GetElement(br->GetID());
5815 Int_t offset;
5816 info->GetStreamerElement(element->GetName(),offset);
5817 clonesinfo->fNext = new TFormLeafInfo(cl,offset+br->GetOffset(),element);
5818 last = clonesinfo->fNext;
5821
5822 } else if (br->GetType()==41) {
5823 // sub branch of a Collection
5824
5825 TBranchElement *count = br->GetBranchCount();
5827 if ( count->GetID() >= 0 ) {
5829 (TStreamerElement *)count->GetInfo()->GetElement(count->GetID());
5830 TClass *collectionCl = collectionElement->GetClassPointer();
5831
5834 } else {
5838 }
5839
5840 TStreamerInfo *info = br->GetInfo();
5841 TClass* cl = info->GetClass();
5842 TStreamerElement *element = (TStreamerElement *)info->GetElement(br->GetID());
5843 Int_t offset;
5844 info->GetStreamerElement(element->GetName(),offset);
5845 collectioninfo->fNext = new TFormLeafInfo(cl,offset+br->GetOffset(),element);
5846 last = collectioninfo->fNext;
5849
5850 } else if (br->GetID()<0) {
5851 return false;
5852 } else {
5853 last = new TFormLeafInfoDirect(br);
5854 fDataMembers.AddAtAndExpand(last,code);
5856 }
5857 } else {
5858 //last = new TFormLeafInfoDirect(br);
5859 //fDataMembers.AddAtAndExpand(last,code);
5860 //fLookupType[code]=kDataMember;
5861 return false;
5862 }
5863 }
5864 return true;
5865}
5866
5868{
5869 // TTreeFormula version of AnalyzePrimitive(). Does nothing. Predefined
5870 // primitive functions are not supported by TTreeFormula since they
5871 // operate on x[] and parameters, which are unavailable here.
5872
5873 return kFALSE;
5874}
5875
5877{
5878 // TTreeFormula version of Optimize(). Does nothing. TTreeFormula does not
5879 // support the TFormula-style optimization since it requires variables and
5880 // parameters in fixed locations, which are unavailable here.
5881
5882 return;
5883}
#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
bool Bool_t
Definition RtypesCore.h:63
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
constexpr Bool_t kFALSE
Definition RtypesCore.h:94
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:414
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:1579
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:104
TString * fExpr
Definition TFormula.h:78
virtual Int_t GetNdim() const
Definition TFormula.h:238
Short_t GetAction(Int_t code) const
Definition TFormula.h:105
Int_t GetActionParam(Int_t code) const
Definition TFormula.h:106
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:108
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:293
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:4727
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:3003
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition TClass.cxx:4512
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:3074
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:202
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:201
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
static constexpr Ssiz_t kNPOS
Definition TString.h:278
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
Bool_t AnalyzePrimitive(TString &chain, TObjArray &args, Int_t &err, Int_t offset) override
Check if the given string matches a defined function primitive.
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.
void Optimize() override
MI include.
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:89
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:4890
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:6138
virtual Long64_t GetEntries() const
Definition TTree.h:485
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:6251
virtual Long64_t GetReadEntry() const
Definition TTree.h:571
virtual TObjArray * GetListOfBranches()
Definition TTree.h:550
virtual TTree * GetTree() const
Definition TTree.h:579
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6529
virtual const char * GetAlias(const char *aliasName) const
Returns the expanded value of the alias. Search in the friends if any.
Definition TTree.cxx:5275
virtual Int_t GetTreeNumber() const
Definition TTree.h:581
static TClass * Class()
virtual TLeaf * FindLeaf(const char *name)
Find leaf..
Definition TTree.cxx:4965
virtual const char * GetFriendAlias(TTree *) const
If the 'tree' is a friend, this method returns its alias name.
Definition TTree.cxx:6088
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:1830
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:618
Double_t ACos(Double_t)
Returns the principal value of the arc cosine of x, expressed in radians.
Definition TMath.h:638
Double_t ASin(Double_t)
Returns the principal value of the arc sine of x, expressed in radians.
Definition TMath.h:630
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:715
Double_t ATan(Double_t)
Returns the principal value of the arc tangent of x, expressed in radians.
Definition TMath.h:646
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:624
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:652
Double_t Log(Double_t x)
Returns the natural logarithm of x.
Definition TMath.h:762
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:668
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Returns x raised to the power y.
Definition TMath.h:727
Double_t Cos(Double_t)
Returns the cosine of an angle of x radians.
Definition TMath.h:600
constexpr Double_t Pi()
Definition TMath.h:38
Double_t Sin(Double_t)
Returns the sine of an angle of x radians.
Definition TMath.h:594
Double_t SignalingNaN()
Returns a signaling NaN as defined by IEEE 754](http://en.wikipedia.org/wiki/NaN#Signaling_NaN).
Definition TMath.h:916
Double_t Tan(Double_t)
Returns the tangent of an angle of x radians.
Definition TMath.h:606
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:768
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:124
Double_t SinH(Double_t)
Returns the hyperbolic sine of `x.
Definition TMath.h:612
TCanvas * slash()
Definition slash.C:1
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