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