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