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