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