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