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