Logo ROOT   6.16/01
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 "TBranch.h"
16#include "TBranchObject.h"
17#include "TFunction.h"
18#include "TClonesArray.h"
19#include "TLeafB.h"
20#include "TLeafC.h"
21#include "TLeafObject.h"
22#include "TDataMember.h"
23#include "TMethodCall.h"
24#include "TCutG.h"
25#include "TRandom.h"
26#include "TInterpreter.h"
27#include "TDataType.h"
28#include "TStreamerInfo.h"
29#include "TStreamerElement.h"
30#include "TBranchElement.h"
31#include "TLeafElement.h"
32#include "TArrayI.h"
33#include "TAxis.h"
34#include "TError.h"
36#include "TString.h"
37#include "TTimeStamp.h"
38#include "TMath.h"
39
40#include "TVirtualRefProxy.h"
41#include "TTreeFormulaManager.h"
42#include "TFormLeafInfo.h"
43#include "TMethod.h"
44#include "TBaseClass.h"
46
47#include "TEntryList.h"
48
49#include <ctype.h>
50#include <stdio.h>
51#include <math.h>
52#include <stdlib.h>
53#include <typeinfo>
54#include <algorithm>
55
56const Int_t kMaxLen = 1024;
57
58/** \class TTreeFormula
59Used to pass a selection expression to the Tree drawing routine. See TTree::Draw
60
61A TreeFormula can contain any arithmetic expression including
62standard operators and mathematical functions separated by operators.
63Examples of valid expression:
64~~~{.cpp}
65 "x<y && sqrt(z)>3.2"
66~~~
67TTreeFormula now relies on a variety of TFormLeafInfo classes to handle the
68reading of the information. Here is the list of theses classes:
69 - TFormLeafInfo
70 - TFormLeafInfoDirect
71 - TFormLeafInfoNumerical
72 - TFormLeafInfoClones
73 - TFormLeafInfoCollection
74 - TFormLeafInfoPointer
75 - TFormLeafInfoMethod
76 - TFormLeafInfoMultiVarDim
77 - TFormLeafInfoMultiVarDimDirect
78 - TFormLeafInfoCast
79
80The following method are available from the TFormLeafInfo interface:
81
82 - AddOffset(Int_t offset, TStreamerElement* element)
83 - GetCounterValue(TLeaf* leaf) : return the size of the array pointed to.
84 - GetObjectAddress(TLeafElement* leaf) : Returns the the location of the object pointed to.
85 - GetMultiplicity() : Returns info on the variability of the number of elements
86 - GetNdata(TLeaf* leaf) : Returns the number of elements
87 - GetNdata() : Used by GetNdata(TLeaf* leaf)
88 - GetValue(TLeaf *leaf, Int_t instance = 0) : Return the value
89 - GetValuePointer(TLeaf *leaf, Int_t instance = 0) : Returns the address of the value
90 - GetLocalValuePointer(TLeaf *leaf, Int_t instance = 0) : Returns the address of the value of 'this' LeafInfo
91 - IsString()
92 - ReadValue(char *where, Int_t instance = 0) : Internal function to interpret the location 'where'
93 - Update() : react to the possible loading of a shared library.
94*/
95
97
98////////////////////////////////////////////////////////////////////////////////
99
100inline static void R__LoadBranch(TBranch* br, Long64_t entry, Bool_t quickLoad)
101{
102 if (!quickLoad || (br->GetReadEntry() != entry)) {
103 br->GetEntry(entry);
104 }
105}
106
107////////////////////////////////////////////////////////////////////////////////
108/// \class TDimensionInfo
109/// A small helper class to help in keeping track of the array
110/// dimensions encountered in the analysis of the expression.
111
112class TDimensionInfo : public TObject {
113public:
114 Int_t fCode; // Location of the leaf in TTreeFormula::fCode
115 Int_t fOper; // Location of the Helper using the leaf in TTreeFormula::fOper
116 Int_t fSize;
117 TFormLeafInfoMultiVarDim* fMultiDim;
118 TDimensionInfo(Int_t code, Int_t oper, Int_t size, TFormLeafInfoMultiVarDim* multiDim)
119 : fCode(code), fOper(oper), fSize(size), fMultiDim(multiDim) {};
120 ~TDimensionInfo() {};
121};
122
123////////////////////////////////////////////////////////////////////////////////
124
125TTreeFormula::TTreeFormula(): ROOT::v5::TFormula(), fQuickLoad(kFALSE), fNeedLoading(kTRUE),
126 fDidBooleanOptimization(kFALSE), fDimensionSetup(0)
127
128{
129 // Tree Formula default constructor
130
131 fTree = 0;
132 fLookupType = 0;
133 fNindex = 0;
134 fNcodes = 0;
135 fAxis = 0;
136 fHasCast = 0;
137 fManager = 0;
138 fMultiplicity = 0;
139 fConstLD = 0;
140
141 Int_t j,k;
142 for (j=0; j<kMAXCODES; j++) {
143 fNdimensions[j] = 0;
144 fCodes[j] = 0;
145 fNdata[j] = 1;
147 for (k = 0; k<kMAXFORMDIM; k++) {
148 fIndexes[j][k] = -1;
149 fCumulSizes[j][k] = 1;
150 fVarIndexes[j][k] = 0;
151 }
152 }
153}
154
155////////////////////////////////////////////////////////////////////////////////
156/// Normal TTree Formula Constuctor
157
158TTreeFormula::TTreeFormula(const char *name,const char *expression, TTree *tree)
159 :ROOT::v5::TFormula(), fTree(tree), fQuickLoad(kFALSE), fNeedLoading(kTRUE),
160 fDidBooleanOptimization(kFALSE), fDimensionSetup(0)
161{
162 Init(name,expression);
163}
164
165////////////////////////////////////////////////////////////////////////////////
166/// Constructor used during the expansion of an alias
167
168TTreeFormula::TTreeFormula(const char *name,const char *expression, TTree *tree,
169 const std::vector<std::string>& aliases)
170 :ROOT::v5::TFormula(), fTree(tree), fQuickLoad(kFALSE), fNeedLoading(kTRUE),
171 fDidBooleanOptimization(kFALSE), fDimensionSetup(0), fAliasesUsed(aliases)
172{
173 Init(name,expression);
174}
175
176////////////////////////////////////////////////////////////////////////////////
177/// Initialiation called from the constructors.
178
179void TTreeFormula::Init(const char*name, const char* expression)
180{
181 TDirectory *const savedir=gDirectory;
182
185 fNcodes = 0;
186 fMultiplicity = 0;
187 fAxis = 0;
188 fHasCast = 0;
189 fConstLD = 0;
190 Int_t i,j,k;
192 fManager->Add(this);
193
194 for (j=0; j<kMAXCODES; j++) {
195 fNdimensions[j] = 0;
196 fLookupType[j] = kDirect;
197 fCodes[j] = 0;
198 fNdata[j] = 1;
200 for (k = 0; k<kMAXFORMDIM; k++) {
201 fIndexes[j][k] = -1;
202 fCumulSizes[j][k] = 1;
203 fVarIndexes[j][k] = 0;
204 }
205 }
206
208
209 if (Compile(expression)) {
210 fTree = 0; fNdim = 0;
211 if(savedir) savedir->cd();
212 return;
213 }
214
215 if (fNcodes >= kMAXFOUND) {
216 Warning("TTreeFormula","Too many items in expression:%s",expression);
218 }
219 SetName(name);
220
221 for (i=0;i<fNoper;i++) {
222
223 if (GetAction(i)==kDefinedString) {
224 Int_t string_code = GetActionParam(i);
225 TLeaf *leafc = (TLeaf*)fLeaves.UncheckedAt(string_code);
226 if (!leafc) continue;
227
228 // We have a string used as a string
229
230 // This dormant portion of code would be used if (when?) we allow the histogramming
231 // of the integral content (as opposed to the string content) of strings
232 // held in a variable size container delimited by a null (as opposed to
233 // a fixed size container or variable size container whose size is controlled
234 // by a variable). In GetNdata, we will then use strlen to grab the current length.
235 //fCumulSizes[i][fNdimensions[i]-1] = 1;
236 //fUsedSizes[fNdimensions[i]-1] = -TMath::Abs(fUsedSizes[fNdimensions[i]-1]);
237 //fUsedSizes[0] = - TMath::Abs( fUsedSizes[0]);
238
239 if (fNoper == 1) {
240 // If the string is by itself, then it can safely be histogrammed as
241 // in a string based axis. To histogram the number inside the string
242 // just make it part of a useless expression (for example: mystring+0)
244 }
245 continue;
246 }
247 if (GetAction(i)==kJump && GetActionParam(i)==(fNoper-1)) {
248 // We have cond ? string1 : string2
250 }
251 }
252 if (fNoper == 1 && GetAction(0)==kStringConst) {
254 }
255 if (fNoper==1 && GetAction(0)==kAliasString) {
256 TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
257 R__ASSERT(subform);
258 if (subform->IsString()) SetBit(kIsCharacter);
259 } else if (fNoper==2 && GetAction(0)==kAlternateString) {
260 TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
261 R__ASSERT(subform);
262 if (subform->IsString()) SetBit(kIsCharacter);
263 }
264
265 fManager->Sync();
266
267 // Let's verify the indexes and dies if we need to.
268 Int_t k0,k1;
269 for(k0 = 0; k0 < fNcodes; k0++) {
270 for(k1 = 0; k1 < fNdimensions[k0]; k1++ ) {
271 // fprintf(stderr,"Saw %d dim %d and index %d\n",k1, fFixedSizes[k0][k1], fIndexes[k0][k1]);
272 if ( fIndexes[k0][k1]>=0 && fFixedSizes[k0][k1]>=0
273 && fIndexes[k0][k1]>=fFixedSizes[k0][k1]) {
274 Error("TTreeFormula",
275 "Index %d for dimension #%d in %s is too high (max is %d)",
276 fIndexes[k0][k1],k1+1, expression,fFixedSizes[k0][k1]-1);
277 fTree = 0; fNdim = 0;
278 if(savedir) savedir->cd();
279 return;
280 }
281 }
282 }
283
284 // Create a list of uniques branches to load.
285 for(k=0; k<fNcodes ; k++) {
286 TLeaf *leaf = k <= fLeaves.GetLast() ? (TLeaf*)fLeaves.UncheckedAt(k) : 0;
287 TBranch *branch = 0;
288 if (leaf) {
289 branch = leaf->GetBranch();
290 if (fBranches.FindObject(branch)) branch = 0;
291 }
292 fBranches.AddAtAndExpand(branch,k);
293 }
294
296
298 // Call TTree::GetEntries() to insure that it is already calculated.
299 // This will need to be done anyway at the first iteration and insure
300 // that it will not mess up the branch reading (because TTree::GetEntries
301 // opens all the file in the chain and 'stays' on the last file.
302
303 Long64_t readentry = fTree->GetReadEntry();
304 Int_t treenumber = fTree->GetTreeNumber();
305 fTree->GetEntries();
306 if (treenumber != fTree->GetTreeNumber()) {
307 if (readentry >= 0) {
308 fTree->LoadTree(readentry);
309 }
311 } else {
312 if (readentry >= 0) {
313 fTree->LoadTree(readentry);
314 }
315 }
316
317 }
318
319 if(savedir) savedir->cd();
320}
321
322////////////////////////////////////////////////////////////////////////////////
323/// Tree Formula default destructor.
324
326{
327 if (fManager) {
328 fManager->Remove(this);
329 if (fManager->fFormulas.GetLast()<0) {
330 delete fManager;
331 fManager = 0;
332 }
333 }
334 // Objects in fExternalCuts are not owned and should not be deleted
335 // fExternalCuts.Clear();
340 if (fLookupType) delete [] fLookupType;
341 for (int j=0; j<fNcodes; j++) {
342 for (int k = 0; k<fNdimensions[j]; k++) {
343 if (fVarIndexes[j][k]) delete fVarIndexes[j][k];
344 fVarIndexes[j][k] = 0;
345 }
346 }
347 if (fDimensionSetup) {
349 delete fDimensionSetup;
350 }
351 delete[] fConstLD;
352}
353
354////////////////////////////////////////////////////////////////////////////////
355/// This method is used internally to decode the dimensions of the variables.
356
359 Int_t& virt_dim) {
360 if (info) {
362 //if (fIndexes[code][info->fDim]<0) { // removed because the index might be out of bounds!
363 info->fVirtDim = virt_dim;
364 fManager->AddVarDims(virt_dim); // if (!fVarDims[virt_dim]) fVarDims[virt_dim] = new TArrayI;
365 //}
366 }
367
368 Int_t vsize = 0;
369
370 if (fIndexes[code][fNdimensions[code]]==-2) {
371 TTreeFormula *indexvar = fVarIndexes[code][fNdimensions[code]];
372 // ASSERT(indexvar!=0);
373 Int_t index_multiplicity = indexvar->GetMultiplicity();
374 switch (index_multiplicity) {
375 case -1:
376 case 0:
377 case 2:
378 vsize = indexvar->GetNdata();
379 break;
380 case 1:
381 vsize = -1;
382 break;
383 };
384 } else vsize = size;
385
386 fCumulSizes[code][fNdimensions[code]] = size;
387
388 if ( fIndexes[code][fNdimensions[code]] < 0 ) {
389 fManager->UpdateUsedSize(virt_dim, vsize);
390 }
391
392 fNdimensions[code] ++;
393
394}
395
396////////////////////////////////////////////////////////////////////////////////
397/// This method is used internally to decode the dimensions of the variables.
398
400{
401 // We assume that there are NO white spaces in the info string
402 const char * current;
403 Int_t size, scanindex, vardim;
404
405 current = info;
406 vardim = 0;
407 // the next value could be before the string but
408 // that's okay because the next operation is ++
409 // (this is to avoid (?) a if statement at the end of the
410 // loop)
411 if (current[0] != '[') current--;
412 while (current) {
413 current++;
414 scanindex = sscanf(current,"%d",&size);
415 // if scanindex is 0 then we have a name index thus a variable
416 // array (or TClonesArray!).
417
418 if (scanindex==0) size = -1;
419
420 vardim += RegisterDimensions(code, size);
421
422 if (fNdimensions[code] >= kMAXFORMDIM) {
423 // NOTE: test that fNdimensions[code] is NOT too big!!
424
425 break;
426 }
427 current = (char*)strstr( current, "[" );
428 }
429 return vardim;
430}
431
432
433////////////////////////////////////////////////////////////////////////////////
434/// This method stores the dimension information for later usage.
435
437 TDimensionInfo * info = new TDimensionInfo(code,fNoper,size,multidim);
438 fDimensionSetup->Add(info);
439 fCumulSizes[code][fNdimensions[code]] = size;
440 fNdimensions[code] ++;
441 return (size==-1) ? 1 : 0;
442}
443
444////////////////////////////////////////////////////////////////////////////////
445/// This method is used internally to decode the dimensions of the variables.
446
448 TFormLeafInfo * /* maininfo */,
449 Bool_t useCollectionObject) {
450 Int_t ndim, size, current, vardim;
451 vardim = 0;
452
453 const TStreamerElement * elem = leafinfo->fElement;
454 TClass* c = elem ? elem->GetClassPointer() : 0;
455
456 TFormLeafInfoMultiVarDim * multi = dynamic_cast<TFormLeafInfoMultiVarDim * >(leafinfo);
457 if (multi) {
458 // We have a second variable dimensions
460 multi->fDim = fNdimensions[code];
461 return RegisterDimensions(code, -1, multi);
462 }
463 if (elem->IsA() == TStreamerBasicPointer::Class()) {
464
465 if (elem->GetArrayDim()>0) {
466
467 ndim = elem->GetArrayDim();
468 size = elem->GetMaxIndex(0);
469 vardim += RegisterDimensions(code, -1);
470 } else {
471 ndim = 1;
472 size = -1;
473 }
474
476 TClass *cl = leafinfo->fClass;
477 Int_t offset;
478 TStreamerElement* counter = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(array->GetCountName(),offset);
479#if 1
480 leafinfo->fCounter = new TFormLeafInfo(cl,offset,counter);
481#else /* Code is not ready yet see revision 14078 */
482 if (maininfo==0 || maininfo==leafinfo || 1) {
483 leafinfo->fCounter = new TFormLeafInfo(cl,offset,counter);
484 } else {
485 leafinfo->fCounter = maininfo->DeepCopy();
486 TFormLeafInfo *currentinfo = leafinfo->fCounter;
487 while(currentinfo->fNext && currentinfo->fNext->fNext) currentinfo=currentinfo->fNext;
488 delete currentinfo->fNext;
489 currentinfo->fNext = new TFormLeafInfo(cl,offset,counter);
490 }
491#endif
492 } else if (!useCollectionObject && elem->GetClassPointer() == TClonesArray::Class() ) {
493
494 ndim = 1;
495 size = -1;
496
497 TClass * clonesClass = TClonesArray::Class();
498 Int_t c_offset;
499 TStreamerElement *counter = ((TStreamerInfo*)clonesClass->GetStreamerInfo())->GetStreamerElement("fLast",c_offset);
500 leafinfo->fCounter = new TFormLeafInfo(clonesClass,c_offset,counter);
501
502 } else if (!useCollectionObject && elem->GetClassPointer() && elem->GetClassPointer()->GetCollectionProxy() ) {
503
504 if ( typeid(*leafinfo) == typeid(TFormLeafInfoCollection) ) {
505 ndim = 1;
506 size = -1;
507 } else {
509 ndim = 1;
510 size = 1;
511 }
512
513 } else if ( c && c->GetReferenceProxy() && c->GetReferenceProxy()->HasCounter() ) {
514 ndim = 1;
515 size = -1;
516 } else if (elem->GetArrayDim()>0) {
517
518 ndim = elem->GetArrayDim();
519 size = elem->GetMaxIndex(0);
520
521 } else if ( elem->GetNewType()== TStreamerInfo::kCharStar) {
522
523 // When we implement being able to read the length from
524 // strlen, we will have:
525 // ndim = 1;
526 // size = -1;
527 // until then we more or so die:
528 ndim = 1;
529 size = 1; //NOTE: changed from 0
530
531 } else return 0;
532
533 current = 0;
534 do {
535 vardim += RegisterDimensions(code, size);
536
537 if (fNdimensions[code] >= kMAXFORMDIM) {
538 // NOTE: test that fNdimensions[code] is NOT too big!!
539
540 break;
541 }
542 current++;
543 size = elem->GetMaxIndex(current);
544 } while (current<ndim);
545
546 return vardim;
547}
548
549////////////////////////////////////////////////////////////////////////////////
550/// This method is used internally to decode the dimensions of the variables.
551
553 TBranchElement * leafcount2 = branch->GetBranchCount2();
554 if (leafcount2) {
555 // With have a second variable dimensions
556 TBranchElement *leafcount = dynamic_cast<TBranchElement*>(branch->GetBranchCount());
557
558 R__ASSERT(leafcount); // The function should only be called on a functional TBranchElement object
559
562 fDataMembers.AddAtAndExpand(info, code);
564
565 info->fCounter = new TFormLeafInfoDirect(leafcount);
566 info->fCounter2 = new TFormLeafInfoDirect(leafcount2);
567 info->fDim = fNdimensions[code];
568 //if (fIndexes[code][info->fDim]<0) {
569 // info->fVirtDim = virt_dim;
570 // if (!fVarDims[virt_dim]) fVarDims[virt_dim] = new TArrayI;
571 //}
572 return RegisterDimensions(code, -1, info);
573 }
574 return 0;
575}
576
577////////////////////////////////////////////////////////////////////////////////
578/// This method is used internally to decode the dimensions of the variables.
579
581 Int_t numberOfVarDim = 0;
582
583 // Let see if we can understand the structure of this branch.
584 // Usually we have: leafname[fixed_array] leaftitle[var_array]\type
585 // (with fixed_array that can be a multi-dimension array.
586 const char *tname = leaf->GetTitle();
587 char *leaf_dim = (char*)strstr( tname, "[" );
588
589 const char *bname = leaf->GetBranch()->GetName();
590 char *branch_dim = (char*)strstr(bname,"[");
591 if (branch_dim) branch_dim++; // skip the '['
592
593 Bool_t isString = kFALSE;
594 if (leaf->IsA() == TLeafElement::Class()) {
595 Int_t type =((TBranchElement*)leaf->GetBranch())->GetStreamerType();
598 } else {
599 isString = (leaf->IsA() == TLeafC::Class());
600 }
601 if (leaf_dim) {
602 leaf_dim++; // skip the '['
603 if (!branch_dim || strncmp(branch_dim,leaf_dim,strlen(branch_dim))) {
604 // then both are NOT the same so do the leaf title first:
605 numberOfVarDim += RegisterDimensions( leaf_dim, code);
606 } else if (branch_dim && strncmp(branch_dim,leaf_dim,strlen(branch_dim))==0
607 && strlen(leaf_dim)>strlen(branch_dim)
608 && (leaf_dim+strlen(branch_dim))[0]=='[') {
609 // we have extra info in the leaf title
610 numberOfVarDim += RegisterDimensions( leaf_dim+strlen(branch_dim)+1, code);
611 }
612 }
613 if (branch_dim) {
614 // then both are NOT same so do the branch name next:
615 if (isString) {
616 numberOfVarDim += RegisterDimensions( code, 1);
617 } else {
618 numberOfVarDim += RegisterDimensions( branch_dim, code);
619 }
620 }
621 if (leaf->IsA() == TLeafElement::Class()) {
622 TBranchElement* branch = (TBranchElement*) leaf->GetBranch();
623 if (branch->GetBranchCount2()) {
624
625 if (!branch->GetBranchCount()) {
626 Warning("DefinedVariable",
627 "Noticed an incorrect in-memory TBranchElement object (%s).\nIt has a BranchCount2 but no BranchCount!\nThe result might be incorrect!",
628 branch->GetName());
629 return numberOfVarDim;
630 }
631
632 // Switch from old direct style to using a TLeafInfo
633 if (fLookupType[code] == kDataMember)
634 Warning("DefinedVariable",
635 "Already in kDataMember mode when handling multiple variable dimensions");
636 fLookupType[code] = kDataMember;
637
638 // Feed the information into the Dimensions system
639 numberOfVarDim += RegisterDimensions( code, branch);
640
641 }
642 }
643 return numberOfVarDim;
644}
645
646////////////////////////////////////////////////////////////////////////////////
647/// This method check for treat the case where expression contains $Atl and load up
648/// both fAliases and fExpr.
649/// We return:
650/// - -1 in case of failure
651/// - 0 in case we did not find $Alt
652/// - the action number in case of success.
653
655{
656 static const char *altfunc = "Alt$(";
657 static const char *minfunc = "MinIf$(";
658 static const char *maxfunc = "MaxIf$(";
659 Int_t action = 0;
660 Int_t start = 0;
661
662 if ( strncmp(expression,altfunc,strlen(altfunc))==0
663 && expression[strlen(expression)-1]==')' ) {
664 action = kAlternate;
665 start = strlen(altfunc);
666 }
667 if ( strncmp(expression,maxfunc,strlen(maxfunc))==0
668 && expression[strlen(expression)-1]==')' ) {
669 action = kMaxIf;
670 start = strlen(maxfunc);
671 }
672 if ( strncmp(expression,minfunc,strlen(minfunc))==0
673 && expression[strlen(expression)-1]==')' ) {
674 action = kMinIf;
675 start = strlen(minfunc);
676 }
677
678 if (action) {
679 TString full = expression;
680 TString part1;
681 TString part2;
682 int paran = 0;
683 int instr = 0;
684 int brack = 0;
685 for(unsigned int i=start;i<strlen(expression);++i) {
686 switch (expression[i]) {
687 case '(': paran++; break;
688 case ')': paran--; break;
689 case '"': instr = instr ? 0 : 1; break;
690 case '[': brack++; break;
691 case ']': brack--; break;
692 };
693 if (expression[i]==',' && paran==0 && instr==0 && brack==0) {
694 part1 = full( start, i-start );
695 part2 = full( i+1, full.Length() -1 - (i+1) );
696 break; // out of the for loop
697 }
698 }
699 if (part1.Length() && part2.Length()) {
700 TTreeFormula *primary = new TTreeFormula("primary",part1,fTree);
701 TTreeFormula *alternate = new TTreeFormula("alternate",part2,fTree);
702
703 short isstring = 0;
704
705 if (action == kAlternate) {
706 if (alternate->GetManager()->GetMultiplicity() != 0 ) {
707 Error("DefinedVariable","The 2nd arguments in %s can not be an array (%s,%d)!",
708 expression,alternate->GetTitle(),
709 alternate->GetManager()->GetMultiplicity());
710 return -1;
711 }
712
713 // Should check whether we have strings.
714 if (primary->IsString()) {
715 if (!alternate->IsString()) {
716 Error("DefinedVariable",
717 "The 2nd arguments in %s has to return the same type as the 1st argument (string)!",
718 expression);
719 return -1;
720 }
721 isstring = 1;
722 } else if (alternate->IsString()) {
723 Error("DefinedVariable",
724 "The 2nd arguments in %s has to return the same type as the 1st argument (numerical type)!",
725 expression);
726 return -1;
727 }
728 } else {
729 primary->GetManager()->Add( alternate );
730 primary->GetManager()->Sync();
731 if (primary->IsString() || alternate->IsString()) {
732 if (!alternate->IsString()) {
733 Error("DefinedVariable",
734 "The arguments of %s can not be strings!",
735 expression);
736 return -1;
737 }
738 }
739 }
740
742 fExpr[fNoper] = "";
743 SetAction(fNoper, (Int_t)action + isstring, 0 );
744 ++fNoper;
745
746 fAliases.AddAtAndExpand(alternate,fNoper);
747 return (Int_t)kAlias + isstring;
748 }
749 }
750 return 0;
751}
752
753////////////////////////////////////////////////////////////////////////////////
754/// Decompose 'expression' as pointing to something inside the leaf
755/// Returns:
756/// - -2 Error: some information is missing (message already printed)
757/// - -1 Error: Syntax is incorrect (message already printed)
758/// - 0
759/// - >0 the value returns is the action code.
760
761Int_t TTreeFormula::ParseWithLeaf(TLeaf* leaf, const char* subExpression, Bool_t final, UInt_t paran_level, TObjArray& castqueue, Bool_t useLeafCollectionObject, const char* fullExpression)
762{
763 Int_t action = 0;
764
765 Int_t numberOfVarDim = 0;
766 char *current;
767
768 char scratch[kMaxLen]; scratch[0] = '\0';
769 char work[kMaxLen]; work[0] = '\0';
770
771 const char *right = subExpression;
772 TString name = fullExpression;
773
774 TBranch *branch = leaf ? leaf->GetBranch() : 0;
775 Long64_t readentry = fTree->GetTree()->GetReadEntry();
776 if (readentry < 0) readentry=0;
777
778 Bool_t useLeafReferenceObject = false;
779 Int_t code = fNcodes-1;
780
781 // Make a check to prevent problem with some corrupted files (missing TStreamerInfo).
782 if (leaf && leaf->IsA()==TLeafElement::Class()) {
783 TBranchElement *br = 0;
784 if( branch->IsA() == TBranchElement::Class() )
785 {
786 br = ((TBranchElement*)branch);
787
788 if ( br->GetInfo() == 0 ) {
789 Error("DefinedVariable","Missing StreamerInfo for %s. We will be unable to read!",
790 name.Data());
791 return -2;
792 }
793 }
794
795 TBranch *bmom = branch->GetMother();
796 if( bmom->IsA() == TBranchElement::Class() )
797 {
799 if (mom!=br) {
800 if (mom->GetInfo()==0) {
801 Error("DefinedVariable","Missing StreamerInfo for %s."
802 " We will be unable to read!",
803 mom->GetName());
804 return -2;
805 }
806 if ((mom->GetType()) < -1 && !mom->GetAddress()) {
807 Error("DefinedVariable", "Address not set when the type of the branch is negative for for %s. We will be unable to read!", mom->GetName());
808 return -2;
809 }
810 }
811 }
812 }
813
814 // We need to record the location in the list of leaves because
815 // the tree might actually be a chain and in that case the leaf will
816 // change from tree to tree!.
817
818 // Let's reconstruct the name of the leaf, including the possible friend alias
819 TTree *realtree = fTree->GetTree();
820 const char* alias = 0;
821 if (leaf) {
822 if (realtree) alias = realtree->GetFriendAlias(leaf->GetBranch()->GetTree());
823 if (!alias && realtree!=fTree) {
824 // Let's try on the chain
825 alias = fTree->GetFriendAlias(leaf->GetBranch()->GetTree());
826 }
827 }
828 if (alias) snprintf(scratch,kMaxLen-1,"%s.%s",alias,leaf->GetName());
829 else if (leaf) strlcpy(scratch,leaf->GetName(),kMaxLen);
830
831 TTree *tleaf = realtree;
832 if (leaf) {
833 tleaf = leaf->GetBranch()->GetTree();
834 fCodes[code] = tleaf->GetListOfLeaves()->IndexOf(leaf);
835 const char *mother_name = leaf->GetBranch()->GetMother()->GetName();
836 TString br_extended_name; // Could do ( strlen(mother_name)+strlen( leaf->GetBranch()->GetName() ) + 2 )
837 if (leaf->GetBranch()!=leaf->GetBranch()->GetMother()) {
838 if (mother_name[strlen(mother_name)-1]!='.') {
839 br_extended_name = mother_name;
840 br_extended_name.Append('.');
841 }
842 }
843 br_extended_name.Append( leaf->GetBranch()->GetName() );
844 Ssiz_t dim = br_extended_name.First('[');
845 if (dim >= 0) br_extended_name.Remove(dim);
846
847 TNamed *named = new TNamed(scratch,br_extended_name.Data());
848 fLeafNames.AddAtAndExpand(named,code);
849 fLeaves.AddAtAndExpand(leaf,code);
850 }
851
852 // If the leaf belongs to a friend tree which has an index, we might
853 // be in the case where some entry do not exist.
854 if (tleaf != realtree && tleaf->GetTreeIndex()) {
855 // reset the multiplicity
856 if (fMultiplicity >= 0) fMultiplicity = 1;
857 }
858
859 // Analyze the content of 'right'
860
861 // Try to find out the class (if any) of the object in the leaf.
862 TClass * cl = 0;
863 TFormLeafInfo *maininfo = 0;
864 TFormLeafInfo *previnfo = 0;
865 Bool_t unwindCollection = kFALSE;
866 const static TClassRef stdStringClass = TClass::GetClass("string");
867
868 if (leaf==0) {
869 TNamed *names = (TNamed*)fLeafNames.UncheckedAt(code);
870 fLeafNames.AddAt(0,code);
871 TTree *what = (TTree*)fLeaves.UncheckedAt(code);
872 fLeaves.AddAt(0,code);
873
874 cl = what ? what->IsA() : TTree::Class();
875 maininfo = new TFormLeafInfoTTree(fTree,names->GetName(),what);
876 previnfo = maininfo;
877
878 delete names;
879 } else if (leaf->InheritsFrom(TLeafObject::Class()) ) {
880 TBranchObject *bobj = (TBranchObject*)leaf->GetBranch();
881 cl = TClass::GetClass(bobj->GetClassName());
882 } else if (leaf->InheritsFrom(TLeafElement::Class())) {
883 TBranchElement *branchEl = (TBranchElement *)leaf->GetBranch();
884 branchEl->SetupAddresses();
885 TStreamerInfo *info = branchEl->GetInfo();
886 TStreamerElement *element = 0;
887 Int_t type = branchEl->GetStreamerType();
888 switch(type) {
901 element = info->GetElement(branchEl->GetID());
902 if (element) cl = element->GetClassPointer();
903 }
904 break;
913 element = info->GetElement(branchEl->GetID());
914 if (element){
915 cl = element->GetClassPointer();
916 }
917 }
918 break;
919 case -1: {
920 cl = info->GetClass();
921 }
922 break;
923 }
924
925 // If we got a class object, we need to verify whether it is on a
926 // split TClonesArray sub branch.
927 if (cl && branchEl->GetBranchCount()) {
928 if (branchEl->GetType()==31) {
929 // This is inside a TClonesArray.
930
931 if (!element) {
932 Warning("DefinedVariable",
933 "Missing TStreamerElement in object in TClonesArray section");
934 return -2;
935 }
936 TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(cl, 0, element, kTRUE);
937
938 // The following code was commmented out because in THIS case
939 // the dimension are actually handled by parsing the title and name of the leaf
940 // and branch (see a little further)
941 // The dimension needs to be handled!
942 // numberOfVarDim += RegisterDimensions(code,clonesinfo);
943
944 maininfo = clonesinfo;
945
946 // We skip some cases because we can assume we have an object.
947 Int_t offset=0;
948 info->GetStreamerElement(element->GetName(),offset);
959 previnfo = new TFormLeafInfoPointer(cl,offset+branchEl->GetOffset(),element);
960 } else {
961 previnfo = new TFormLeafInfo(cl,offset+branchEl->GetOffset(),element);
962 }
963 maininfo->fNext = previnfo;
964 unwindCollection = kTRUE;
965
966 } else if (branchEl->GetType()==41) {
967
968 // This is inside a Collection
969
970 if (!element) {
971 Warning("DefinedVariable","Missing TStreamerElement in object in Collection section");
972 return -2;
973 }
974 // First we need to recover the collection.
975 TBranchElement *count = branchEl->GetBranchCount();
976 TFormLeafInfo* collectioninfo;
977 if ( count->GetID() >= 0 ) {
978 TStreamerElement *collectionElement =
979 count->GetInfo()->GetElement(count->GetID());
980 TClass *collectionCl = collectionElement->GetClassPointer();
981
982 collectioninfo =
983 new TFormLeafInfoCollection(collectionCl, 0, collectionElement, kTRUE);
984 } else {
985 TClass *collectionCl = TClass::GetClass(count->GetClassName());
986 collectioninfo =
987 new TFormLeafInfoCollection(collectionCl, 0, collectionCl, kTRUE);
988 }
989
990 // The following code was commmented out because in THIS case
991 // the dimension are actually handled by parsing the title and name of the leaf
992 // and branch (see a little further)
993 // The dimension needs to be handled!
994 // numberOfVarDim += RegisterDimensions(code,clonesinfo);
995
996 maininfo = collectioninfo;
997
998 // We skip some cases because we can assume we have an object.
999 Int_t offset=0;
1000 info->GetStreamerElement(element->GetName(),offset);
1011 previnfo = new TFormLeafInfoPointer(cl,offset+branchEl->GetOffset(),element);
1012 } else {
1013 previnfo = new TFormLeafInfo(cl,offset+branchEl->GetOffset(),element);
1014 }
1015 maininfo->fNext = previnfo;
1016 unwindCollection = kTRUE;
1017 }
1018 } else if ( branchEl->GetType()==3) {
1019 TFormLeafInfo* clonesinfo;
1020 if (useLeafCollectionObject) {
1021 clonesinfo = new TFormLeafInfoCollectionObject(cl);
1022 } else {
1023 clonesinfo = new TFormLeafInfoClones(cl, 0, kTRUE);
1024 // The dimension needs to be handled!
1025 numberOfVarDim += RegisterDimensions(code,clonesinfo,maininfo,useLeafCollectionObject);
1026
1027 }
1028 maininfo = clonesinfo;
1029 previnfo = maininfo;
1030
1031 } else if (!useLeafCollectionObject && branchEl->GetType()==4) {
1032
1033 TFormLeafInfo* collectioninfo;
1034 if (useLeafCollectionObject) {
1035 collectioninfo = new TFormLeafInfoCollectionObject(cl);
1036 } else {
1037 collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, kTRUE);
1038 // The dimension needs to be handled!
1039 numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,useLeafCollectionObject);
1040 }
1041
1042 maininfo = collectioninfo;
1043 previnfo = maininfo;
1044
1045 } else if (branchEl->GetStreamerType()==-1 && cl && cl->GetCollectionProxy()) {
1046
1047 if (useLeafCollectionObject) {
1048
1049 TFormLeafInfo *collectioninfo = new TFormLeafInfoCollectionObject(cl);
1050 maininfo = collectioninfo;
1051 previnfo = collectioninfo;
1052
1053 } else {
1054 TFormLeafInfo *collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, kTRUE);
1055 // The dimension needs to be handled!
1056 numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
1057
1058 maininfo = collectioninfo;
1059 previnfo = collectioninfo;
1060
1061 if (cl->GetCollectionProxy()->GetValueClass()!=0 &&
1063
1065 cl->GetCollectionProxy()->GetValueClass(),collectioninfo);
1066
1067 fHasMultipleVarDim[code] = kTRUE;
1068 numberOfVarDim += RegisterDimensions(code,multi,maininfo,kFALSE);
1069 previnfo->fNext = multi;
1070 cl = cl->GetCollectionProxy()->GetValueClass();
1071 multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false);
1072 previnfo = multi->fNext;
1073
1074 }
1075 if (cl->GetCollectionProxy()->GetValueClass()==0 &&
1076 cl->GetCollectionProxy()->GetType()>0) {
1077
1078 previnfo->fNext =
1080 previnfo = previnfo->fNext;
1081 } else {
1082 // nothing to do
1083 }
1084 }
1085
1086 } else if (strlen(right)==0 && cl && element && final) {
1087
1088 TClass *elemCl = element->GetClassPointer();
1089 if (!useLeafCollectionObject
1090 && elemCl && elemCl->GetCollectionProxy()
1091 && elemCl->GetCollectionProxy()->GetValueClass()
1093
1094 TFormLeafInfo *collectioninfo =
1095 new TFormLeafInfoCollection(cl, 0, elemCl);
1096
1097 // The dimension needs to be handled!
1098 numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
1099
1100 maininfo = collectioninfo;
1101 previnfo = collectioninfo;
1102
1103 TFormLeafInfo *multi =
1105 elemCl->GetCollectionProxy()->GetValueClass(),
1106 collectioninfo);
1107
1108 fHasMultipleVarDim[code] = kTRUE;
1109 numberOfVarDim += RegisterDimensions(code,multi,maininfo,kFALSE);
1110 previnfo->fNext = multi;
1111 cl = elemCl->GetCollectionProxy()->GetValueClass();
1112 multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false);
1113 previnfo = multi->fNext;
1114
1115 if (cl->GetCollectionProxy()->GetValueClass()==0 &&
1116 cl->GetCollectionProxy()->GetType()>0) {
1117
1118 previnfo->fNext =
1120 previnfo = previnfo->fNext;
1121 }
1122
1123 } else if (!useLeafCollectionObject
1124 && elemCl && elemCl->GetCollectionProxy()
1125 && elemCl->GetCollectionProxy()->GetValueClass()==0
1126 && elemCl->GetCollectionProxy()->GetType()>0) {
1127
1128 // At this point we have an element which is inside a class (which is not
1129 // a collection) and this element of a collection of numerical type.
1130 // (Note: it is not possible to have more than one variable dimension
1131 // unless we were supporting variable size C-style array of collection).
1132
1133 TFormLeafInfo* collectioninfo =
1134 new TFormLeafInfoCollection(cl, 0, elemCl);
1135
1136 // The dimension needs to be handled!
1137 numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
1138
1139 collectioninfo->fNext =
1141
1142 maininfo = collectioninfo;
1143 previnfo = maininfo->fNext;
1144
1145 } else if (!useLeafCollectionObject
1146 && elemCl && elemCl->GetCollectionProxy()) {
1147 if (elemCl->GetCollectionProxy()->GetValueClass()==TString::Class()) {
1148 right = "Data()";
1149 } else if (elemCl->GetCollectionProxy()->GetValueClass()==stdStringClass) {
1150 right = "c_str()";
1151 }
1152
1153 } else if (!element->IsaPointer()) {
1154
1155 maininfo = new TFormLeafInfoDirect(branchEl);
1156 previnfo = maininfo;
1157
1158 }
1159 }
1160 else if ( cl && cl->GetReferenceProxy() ) {
1161 if ( useLeafCollectionObject || fullExpression[0] == '@' || fullExpression[strlen(scratch)] == '@' ) {
1162 useLeafReferenceObject = true;
1163 }
1164 else {
1165 if ( !maininfo ) {
1166 maininfo = previnfo = new TFormLeafInfoReference(cl, element, 0);
1167 numberOfVarDim += RegisterDimensions(code,maininfo,maininfo,kFALSE);
1168 }
1169 TVirtualRefProxy *refproxy = cl->GetReferenceProxy();
1170 for(Long64_t i=0; i<leaf->GetBranch()->GetEntries()-readentry; ++i) {
1171 R__LoadBranch(leaf->GetBranch(), readentry+i, fQuickLoad);
1172 void *refobj = maininfo->GetValuePointer(leaf,0);
1173 if (refobj) {
1174 cl = refproxy->GetValueClass(refobj);
1175 }
1176 if ( cl ) break;
1177 }
1178 if ( !cl ) {
1179 Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1180 return -1;
1181 }
1182 }
1183 }
1184 }
1185
1186 // Treat the dimension information in the leaf name, title and 2nd branch count
1187 if (leaf) numberOfVarDim += RegisterDimensions(code,leaf);
1188
1189 if (cl) {
1190 if (unwindCollection) {
1191 // So far we should get here only if we encounter a split collection of a class that contains
1192 // directly a collection.
1193 R__ASSERT(numberOfVarDim==1 && maininfo);
1194
1195 if (!useLeafCollectionObject && cl && cl->GetCollectionProxy()) {
1196 TFormLeafInfo *multi =
1197 new TFormLeafInfoMultiVarDimCollection(cl, 0, cl, maininfo);
1198 fHasMultipleVarDim[code] = kTRUE;
1199 numberOfVarDim += RegisterDimensions(code,multi,maininfo,kFALSE);
1200 previnfo->fNext = multi;
1201
1202 multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false);
1203 previnfo = multi->fNext;
1204
1205 if (cl->GetCollectionProxy()->GetValueClass()==0 &&
1206 cl->GetCollectionProxy()->GetType()>0) {
1207
1208 previnfo->fNext =
1210 previnfo = previnfo->fNext;
1211 }
1212 } else if (!useLeafCollectionObject && cl == TClonesArray::Class()) {
1213
1214 TFormLeafInfo *multi =
1215 new TFormLeafInfoMultiVarDimClones(cl, 0, cl, maininfo);
1216 fHasMultipleVarDim[code] = kTRUE;
1217 numberOfVarDim += RegisterDimensions(code,multi,maininfo,kFALSE);
1218 previnfo->fNext = multi;
1219
1220 multi->fNext = new TFormLeafInfoClones(cl, 0, false);
1221 previnfo = multi->fNext;
1222 }
1223 }
1224 Int_t offset=0;
1225 if (cl == TString::Class() && strcmp(right,"fData")==0) {
1226 // For backward compatibility replace TString::fData which no longer exist
1227 // by a call to TString::Data()
1228 right = "Data()";
1229 }
1230 Int_t nchname = strlen(right);
1231 TFormLeafInfo *leafinfo = 0;
1232 TStreamerElement* element = 0;
1233
1234 // Let see if the leaf was attempted to be casted.
1235 // Since there would have been something like
1236 // ((cast_class*)leafname)->.... we need to use
1237 // paran_level+1
1238 // Also we disable this functionality in case of TClonesArray
1239 // because it is not yet allowed to have 'inheritance' (or virtuality)
1240 // in play in a TClonesArray.
1241 {
1242 TClass * casted = (TClass*) castqueue.At(paran_level+1);
1243 if (casted && cl != TClonesArray::Class()) {
1244 if ( ! casted->InheritsFrom(cl) ) {
1245 Error("DefinedVariable","%s does not inherit from %s. Casting not possible!",
1246 casted->GetName(),cl->GetName());
1247 return -2;
1248 }
1249 leafinfo = new TFormLeafInfoCast(cl,casted);
1250 fHasCast = kTRUE;
1251 if (maininfo==0) {
1252 maininfo = leafinfo;
1253 }
1254 if (previnfo==0) {
1255 previnfo = leafinfo;
1256 } else {
1257 previnfo->fNext = leafinfo;
1258 previnfo = leafinfo;
1259 }
1260 leafinfo = 0;
1261
1262 cl = casted;
1263 castqueue.AddAt(0,paran_level);
1264 }
1265 }
1266 Int_t i;
1267 Bool_t prevUseCollectionObject = useLeafCollectionObject;
1268 Bool_t useCollectionObject = useLeafCollectionObject;
1269 Bool_t useReferenceObject = useLeafReferenceObject;
1270 Bool_t prevUseReferenceObject = useLeafReferenceObject;
1271 for (i=0, current = &(work[0]); i<=nchname;i++ ) {
1272 // We will treated the terminator as a token.
1273 if (right[i] == '(') {
1274 // Right now we do not allow nested paranthesis
1275 do {
1276 *current++ = right[i++];
1277 } while(right[i]!=')' && right[i]);
1278 *current++ = right[i];
1279 *current='\0';
1280 char *params = strchr(work,'(');
1281 if (params) {
1282 *params = 0; params++;
1283 } else params = (char *) ")";
1284 if (cl==0) {
1285 Error("DefinedVariable","Can not call '%s' with a class",work);
1286 return -1;
1287 }
1288 if (!cl->HasDataMemberInfo() && !cl->GetCollectionProxy()) {
1289 Error("DefinedVariable","Class probably unavailable:%s",cl->GetName());
1290 return -2;
1291 }
1292 if (!useCollectionObject && cl == TClonesArray::Class()) {
1293 // We are not interested in the ClonesArray object but only
1294 // in its contents.
1295 // We need to retrieve the class of its content.
1296
1297 TBranch *clbranch = leaf->GetBranch();
1298 R__LoadBranch(clbranch,readentry,fQuickLoad);
1299 TClonesArray * clones;
1300 if (previnfo) clones = (TClonesArray*)previnfo->GetLocalValuePointer(leaf,0);
1301 else {
1302 Bool_t top = (clbranch==((TBranchElement*)clbranch)->GetMother()
1303 || !leaf->IsOnTerminalBranch());
1304 TClass *mother_cl;
1305 if (leaf->IsA()==TLeafObject::Class()) {
1306 // in this case mother_cl is not really used
1307 mother_cl = cl;
1308 } else {
1309 mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1310 }
1311 TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0, top);
1312
1313 // The dimension needs to be handled!
1314 numberOfVarDim += RegisterDimensions(code,clonesinfo,maininfo,kFALSE);
1315
1316 previnfo = clonesinfo;
1317 maininfo = clonesinfo;
1318
1319 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1320 }
1321 TClass * inside_cl = clones->GetClass();
1322 cl = inside_cl;
1323
1324 }
1325 else if (!useCollectionObject && cl && cl->GetCollectionProxy() ) {
1326
1327 // We are NEVER (for now!) interested in the ClonesArray object but only
1328 // in its contents.
1329 // We need to retrieve the class of its content.
1330
1331 if (previnfo==0) {
1332
1333 Bool_t top = (branch==((TBranchElement*)branch)->GetMother()
1334 || !leaf->IsOnTerminalBranch());
1335
1336 TClass *mother_cl;
1337 if (leaf->IsA()==TLeafObject::Class()) {
1338 // in this case mother_cl is not really used
1339 mother_cl = cl;
1340 } else {
1341 mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
1342 }
1343
1344 TFormLeafInfo* collectioninfo =
1345 new TFormLeafInfoCollection(mother_cl, 0,cl,top);
1346 // The dimension needs to be handled!
1347 numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
1348
1349 previnfo = collectioninfo;
1350 maininfo = collectioninfo;
1351
1352 }
1353
1354 TClass * inside_cl = cl->GetCollectionProxy()->GetValueClass();
1355 if (inside_cl) cl = inside_cl;
1356 else if (cl->GetCollectionProxy()->GetType()>0) {
1357 Warning("DefinedVariable","Can not call method on content of %s in %s\n",
1358 cl->GetName(),name.Data());
1359 return -2;
1360 }
1361 }
1362 TMethodCall *method = 0;
1363 if (cl==0) {
1364 Error("DefinedVariable",
1365 "Could not discover the TClass corresponding to (%s)!",
1366 right);
1367 return -2;
1368 } else if (cl==TClonesArray::Class() && strcmp(work,"size")==0) {
1369 method = new TMethodCall(cl, "GetEntriesFast", "");
1370 } else if (cl->GetCollectionProxy() && strcmp(work,"size")==0) {
1371 if (maininfo==0) {
1372 TFormLeafInfo* collectioninfo=0;
1373 if (useLeafCollectionObject) {
1374
1375 Bool_t top = (branch==((TBranchElement*)branch)->GetMother()
1376 || !leaf->IsOnTerminalBranch());
1377 collectioninfo = new TFormLeafInfoCollectionObject(cl,top);
1378 }
1379 maininfo=previnfo=collectioninfo;
1380 }
1381 leafinfo = new TFormLeafInfoCollectionSize(cl);
1382 cl = 0;
1383 } else {
1384 if (!cl->HasDataMemberInfo()) {
1385 Error("DefinedVariable",
1386 "Can not call method %s on class without dictionary (%s)!",
1387 right,cl->GetName());
1388 return -2;
1389 }
1390 method = new TMethodCall(cl, work, params);
1391 }
1392 if (method) {
1393 if (!method->GetMethod()) {
1394 Error("DefinedVariable","Unknown method:%s in %s",right,cl->GetName());
1395 return -1;
1396 }
1397 switch(method->ReturnType()) {
1398 case TMethodCall::kLong:
1399 leafinfo = new TFormLeafInfoMethod(cl,method);
1400 cl = 0;
1401 break;
1403 leafinfo = new TFormLeafInfoMethod(cl,method);
1404 cl = 0;
1405 break;
1407 leafinfo = new TFormLeafInfoMethod(cl,method);
1408 // 1 will be replaced by -1 when we know how to use strlen
1409 numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0
1410 cl = 0;
1411 break;
1413 {
1414 leafinfo = new TFormLeafInfoMethod(cl,method);
1416 }
1417 break;
1418 default:
1419 Error("DefineVariable","Method %s from %s has an impossible return type %d",
1420 work,cl->GetName(), (Int_t)method->ReturnType());
1421 return -2;
1422 }
1423 }
1424 if (maininfo==0) {
1425 maininfo = leafinfo;
1426 }
1427 if (previnfo==0) {
1428 previnfo = leafinfo;
1429 } else {
1430 previnfo->fNext = leafinfo;
1431 previnfo = leafinfo;
1432 }
1433 leafinfo = 0;
1434 current = &(work[0]);
1435 *current = 0;
1436 prevUseCollectionObject = kFALSE;
1437 prevUseReferenceObject = kFALSE;
1438 useCollectionObject = kFALSE;
1439
1440 if (cl && cl->GetCollectionProxy()) {
1441 if (numberOfVarDim>1) {
1442 Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1443 cl->GetName());
1444 leafinfo = new TFormLeafInfo(cl,0,0);
1445 useCollectionObject = kTRUE;
1446 } else if (numberOfVarDim==0) {
1447 R__ASSERT(maininfo);
1448 leafinfo = new TFormLeafInfoCollection(cl,0,cl);
1449 numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1450 } else if (numberOfVarDim==1) {
1451 R__ASSERT(maininfo);
1452 leafinfo =
1454 (TStreamerElement*)0,maininfo);
1455 previnfo->fNext = leafinfo;
1456 previnfo = leafinfo;
1457 leafinfo = new TFormLeafInfoCollection(cl,0,cl);
1458
1459 fHasMultipleVarDim[code] = kTRUE;
1460 numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1461 }
1462 previnfo->fNext = leafinfo;
1463 previnfo = leafinfo;
1464 leafinfo = 0;
1465 }
1466 continue;
1467 } else if (right[i] == ')') {
1468 // We should have the end of a cast operator. Let's introduce a TFormLeafCast
1469 // in the chain.
1470 TClass * casted = (TClass*) ((int(--paran_level)>=0) ? castqueue.At(paran_level) : 0);
1471 if (casted) {
1472 leafinfo = new TFormLeafInfoCast(cl,casted);
1473 fHasCast = kTRUE;
1474
1475 if (maininfo==0) {
1476 maininfo = leafinfo;
1477 }
1478 if (previnfo==0) {
1479 previnfo = leafinfo;
1480 } else {
1481 previnfo->fNext = leafinfo;
1482 previnfo = leafinfo;
1483 }
1484 leafinfo = 0;
1485 current = &(work[0]);
1486 *current = 0;
1487
1488 cl = casted;
1489 continue;
1490
1491 }
1492 } else if (i > 0 && (right[i] == '.' || right[i] == '[' || right[i] == '\0') ) {
1493 // A delimiter happened let's see if what we have seen
1494 // so far does point to a data member.
1495 Bool_t needClass = kTRUE;
1496 *current = '\0';
1497
1498 // skip it all if there is nothing to look at
1499 if (strlen(work)==0) continue;
1500
1501 prevUseCollectionObject = useCollectionObject;
1502 prevUseReferenceObject = useReferenceObject;
1503 if (work[0]=='@') {
1504 useReferenceObject = kTRUE;
1505 useCollectionObject = kTRUE;
1506 Int_t l = 0;
1507 for(l=0;work[l+1]!=0;++l) work[l] = work[l+1];
1508 work[l] = '\0';
1509 } else if (work[strlen(work)-1]=='@') {
1510 useReferenceObject = kTRUE;
1511 useCollectionObject = kTRUE;
1512 work[strlen(work)-1] = '\0';
1513 } else {
1514 useReferenceObject = kFALSE;
1515 useCollectionObject = kFALSE;
1516 }
1517
1518 Bool_t mustderef = kFALSE;
1519 if ( !prevUseReferenceObject && cl && cl->GetReferenceProxy() ) {
1520 R__LoadBranch(leaf->GetBranch(), readentry, fQuickLoad);
1521 if ( !maininfo ) {
1522 maininfo = previnfo = new TFormLeafInfoReference(cl, element, offset);
1523 if ( cl->GetReferenceProxy()->HasCounter() ) {
1524 numberOfVarDim += RegisterDimensions(code,-1);
1525 }
1526 prevUseReferenceObject = kFALSE;
1527 } else {
1528 previnfo->fNext = new TFormLeafInfoReference(cl, element, offset);
1529 previnfo = previnfo->fNext;
1530 }
1531 TVirtualRefProxy *refproxy = cl->GetReferenceProxy();
1532 cl = 0;
1533 for(Long64_t entry=0; entry<leaf->GetBranch()->GetEntries()-readentry; ++entry) {
1534 R__LoadBranch(leaf->GetBranch(), readentry+i, fQuickLoad);
1535 void *refobj = maininfo->GetValuePointer(leaf,0);
1536 if (refobj) {
1537 cl = refproxy->GetValueClass(refobj);
1538 }
1539 if ( cl ) break;
1540 }
1541 needClass = kFALSE;
1542 mustderef = kTRUE;
1543 }
1544 else if (!prevUseCollectionObject && cl == TClonesArray::Class()) {
1545 // We are not interested in the ClonesArray object but only
1546 // in its contents.
1547 // We need to retrieve the class of its content.
1548
1549 TBranch *clbranch = leaf->GetBranch();
1550 R__LoadBranch(clbranch,readentry,fQuickLoad);
1551 TClonesArray * clones;
1552 if (maininfo) {
1553 clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
1554 } else {
1555 // we have a unsplit TClonesArray leaves
1556 // or we did not yet match any of the sub-branches!
1557
1558 TClass *mother_cl;
1559 if (leaf->IsA()==TLeafObject::Class()) {
1560 // in this case mother_cl is not really used
1561 mother_cl = cl;
1562 } else {
1563 mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1564 }
1565
1566 TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0);
1567 // The dimension needs to be handled!
1568 numberOfVarDim += RegisterDimensions(code,clonesinfo,maininfo,kFALSE);
1569
1570 mustderef = kTRUE;
1571 previnfo = clonesinfo;
1572 maininfo = clonesinfo;
1573
1574 if (clbranch->GetListOfBranches()->GetLast()>=0) {
1575 if (clbranch->IsA() != TBranchElement::Class()) {
1576 Error("DefinedVariable","Unimplemented usage of ClonesArray");
1577 return -2;
1578 }
1579 //clbranch = ((TBranchElement*)clbranch)->GetMother();
1580 clones = (TClonesArray*)((TBranchElement*)clbranch)->GetObject();
1581 } else
1582 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1583 }
1584 // NOTE clones can be zero!
1585 if (clones==0) {
1586 Warning("DefinedVariable",
1587 "TClonesArray object was not retrievable for %s!",
1588 name.Data());
1589 return -1;
1590 }
1591 TClass * inside_cl = clones->GetClass();
1592#if 1
1593 cl = inside_cl;
1594#else
1595/* Maybe we should make those test lead to warning messages */
1596 if (1 || inside_cl) cl = inside_cl;
1597 // if inside_cl is nul ... we have a problem of inconsistency :(
1598 if (0 && strlen(work)==0) {
1599 // However in this case we have NO content :(
1600 // so let get the number of objects
1601 //strcpy(work,"fLast");
1602 }
1603#endif
1604 } else if (!prevUseCollectionObject && cl && cl->GetCollectionProxy() ) {
1605
1606 // We are NEVER interested in the Collection object but only
1607 // in its contents.
1608 // We need to retrieve the class of its content.
1609
1610 TBranch *clbranch = leaf->GetBranch();
1611 R__LoadBranch(clbranch,readentry,fQuickLoad);
1612
1613 if (maininfo==0) {
1614
1615 // we have a unsplit Collection leaf
1616 // or we did not yet match any of the sub-branches!
1617
1618 TClass *mother_cl;
1619 if (leaf->IsA()==TLeafObject::Class()) {
1620 // in this case mother_cl is not really used
1621 mother_cl = cl;
1622 } else {
1623 mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1624 }
1625
1626 TFormLeafInfo* collectioninfo =
1627 new TFormLeafInfoCollection(mother_cl, 0, cl);
1628 // The dimension needs to be handled!
1629 numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
1630
1631 mustderef = kTRUE;
1632 previnfo = collectioninfo;
1633 maininfo = collectioninfo;
1634
1635 } //else if (clbranch->GetStreamerType()==0) {
1636
1637 //}
1638
1639 TClass * inside_cl = cl->GetCollectionProxy()->GetValueClass();
1640
1641 if (!inside_cl) {
1642 Error("DefinedVariable","Could you not find the inner class for %s with coll type = %d",
1643 cl->GetName(),cl->GetCollectionProxy()->GetType());
1644 }
1645 if (!inside_cl && cl->GetCollectionProxy()->GetType() > 0) {
1646 Warning("DefinedVariable","No data member in content of %s in %s\n",
1647 cl->GetName(),name.Data());
1648 }
1649 cl = inside_cl;
1650 // if inside_cl is nul ... we have a problem of inconsistency.
1651 }
1652
1653 if (!cl) {
1654 if (leaf) leaf->GetBranch()->Print();
1655 Warning("DefinedVariable","Missing class for %s!",name.Data());
1656 } else {
1657 element = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1658 }
1659
1660 if (!element && !prevUseCollectionObject) {
1661 // We allow for looking for a data member inside a class inside
1662 // a TClonesArray without mentioning the TClonesArrays variable name
1663 TIter next( cl->GetStreamerInfo()->GetElements() );
1664 TStreamerElement * curelem;
1665 while ((curelem = (TStreamerElement*)next())) {
1666 if (curelem->GetClassPointer() == TClonesArray::Class()) {
1667 Int_t clones_offset = 0;
1668 ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),clones_offset);
1669 TFormLeafInfo* clonesinfo =
1670 new TFormLeafInfo(cl, clones_offset, curelem);
1671 TClonesArray * clones;
1672 R__LoadBranch(leaf->GetBranch(),readentry,fQuickLoad);
1673
1674 if (previnfo) {
1675 previnfo->fNext = clonesinfo;
1676 clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
1677 previnfo->fNext = 0;
1678 } else {
1679 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1680 }
1681
1682 TClass *sub_cl = clones->GetClass();
1683 if (sub_cl) element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1684 delete clonesinfo;
1685
1686 if (element) {
1687 leafinfo = new TFormLeafInfoClones(cl,clones_offset,curelem);
1688 numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1689 if (maininfo==0) maininfo = leafinfo;
1690 if (previnfo==0) previnfo = leafinfo;
1691 else {
1692 previnfo->fNext = leafinfo;
1693 previnfo = leafinfo;
1694 }
1695 leafinfo = 0;
1696 cl = sub_cl;
1697 break;
1698 }
1699 } else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {
1700
1701 Int_t coll_offset = 0;
1702 ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),coll_offset);
1703
1704 TClass *sub_cl =
1706 if (sub_cl) {
1707 element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1708 }
1709 if (element) {
1710 if (numberOfVarDim>1) {
1711 Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1712 curelem->GetName());
1713 leafinfo = new TFormLeafInfo(cl,coll_offset,curelem);
1714 useCollectionObject = kTRUE;
1715 } else if (numberOfVarDim==1) {
1716 R__ASSERT(maininfo);
1717 leafinfo =
1718 new TFormLeafInfoMultiVarDimCollection(cl,coll_offset,
1719 curelem,maininfo);
1720 fHasMultipleVarDim[code] = kTRUE;
1721 leafinfo->fNext = new TFormLeafInfoCollection(cl,coll_offset,curelem);
1722 numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1723 } else {
1724 leafinfo = new TFormLeafInfoCollection(cl,coll_offset,curelem);
1725 numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1726 }
1727 if (maininfo==0) maininfo = leafinfo;
1728 if (previnfo==0) previnfo = leafinfo;
1729 else {
1730 previnfo->fNext = leafinfo;
1731 previnfo = leafinfo;
1732 }
1733 if (leafinfo->fNext) {
1734 previnfo = leafinfo->fNext;
1735 }
1736 leafinfo = 0;
1737 cl = sub_cl;
1738 break;
1739 }
1740 }
1741 }
1742
1743 }
1744
1745 if (element) {
1746 Int_t type = element->GetNewType();
1747 if (type<60 && type!=0) {
1748 // This is a basic type ...
1749 if (numberOfVarDim>=1 && type>40) {
1750 // We have a variable array within a variable array!
1751 leafinfo = new TFormLeafInfoMultiVarDim(cl,offset,element,maininfo);
1752 fHasMultipleVarDim[code] = kTRUE;
1753 } else {
1754 if (leafinfo && type<=40 ) {
1755 leafinfo->AddOffset(offset,element);
1756 } else {
1757 leafinfo = new TFormLeafInfo(cl,offset,element);
1758 }
1759 }
1760 } else {
1761 Bool_t object = kFALSE;
1762 Bool_t pointer = kFALSE;
1763 Bool_t objarr = kFALSE;
1764 switch(type) {
1775 pointer = kTRUE;
1776 break;
1778 case TStreamerInfo::kAny :
1784 object = kTRUE;
1785 break;
1789 objarr = kTRUE;
1790 break;
1793 // Unsupported case.
1794 Error("DefinedVariable",
1795 "%s is a datamember of %s BUT is not yet of a supported type (%d)",
1796 right,cl ? cl->GetName() : "unknown class",type);
1797 return -2;
1798 default:
1799 // Unknown and Unsupported case.
1800 Error("DefinedVariable",
1801 "%s is a datamember of %s BUT is not of a unknown type (%d)",
1802 right,cl ? cl->GetName() : "unknown class",type);
1803 return -2;
1804 }
1805
1806 if (object && !useCollectionObject &&
1807 ( element->GetClassPointer() == TClonesArray::Class()
1808 || element->GetClassPointer()->GetCollectionProxy() ) )
1809 {
1810 object = kFALSE;
1811 }
1812 if (object && leafinfo) {
1813 leafinfo->AddOffset(offset,element);
1814 } else if (objarr) {
1815 // This is an embedded array of objects. We can not increase the offset.
1816 leafinfo = new TFormLeafInfo(cl,offset,element);
1817 mustderef = kTRUE;
1818 } else {
1819
1820 if (!useCollectionObject && element->GetClassPointer() == TClonesArray::Class()) {
1821
1822 leafinfo = new TFormLeafInfoClones(cl,offset,element);
1823 mustderef = kTRUE;
1824
1825 } else if (!useCollectionObject && element->GetClassPointer()
1826 && element->GetClassPointer()->GetCollectionProxy()) {
1827
1828 mustderef = kTRUE;
1829 if (numberOfVarDim>1) {
1830 Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1831 element->GetName());
1832 leafinfo = new TFormLeafInfo(cl,offset,element);
1833 useCollectionObject = kTRUE;
1834 } else if (numberOfVarDim==1) {
1835 R__ASSERT(maininfo);
1836 leafinfo =
1837 new TFormLeafInfoMultiVarDimCollection(cl,offset,element,maininfo);
1838
1839 fHasMultipleVarDim[code] = kTRUE;
1840 //numberOfVarDim += RegisterDimensions(code,leafinfo);
1841 //cl = cl->GetCollectionProxy()->GetValueClass();
1842
1843 //if (maininfo==0) maininfo = leafinfo;
1844 //if (previnfo==0) previnfo = leafinfo;
1845 //else {
1846 // previnfo->fNext = leafinfo;
1847 // previnfo = leafinfo;
1848 //}
1849 leafinfo->fNext = new TFormLeafInfoCollection(cl, offset, element);
1850 if (element->GetClassPointer()->GetCollectionProxy()->GetValueClass()==0) {
1852 element->GetClassPointer()->GetCollectionProxy());
1853 if (leafinfo->fNext) leafinfo->fNext->fNext = info;
1854 else leafinfo->fNext = info;
1855 }
1856 } else {
1857 leafinfo = new TFormLeafInfoCollection(cl, offset, element);
1858
1859 TClass *elemCl = element->GetClassPointer();
1860 TClass *valueCl = elemCl->GetCollectionProxy()->GetValueClass();
1861 if (!maininfo) maininfo = leafinfo;
1862
1863 if (valueCl!=0 && valueCl->GetCollectionProxy()!=0) {
1864
1865 numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1866 if (previnfo==0) previnfo = leafinfo;
1867 else {
1868 previnfo->fNext = leafinfo;
1869 previnfo = leafinfo;
1870 }
1871 leafinfo = new TFormLeafInfoMultiVarDimCollection(elemCl,0,
1872 elemCl->GetCollectionProxy()->GetValueClass(),maininfo);
1873 //numberOfVarDim += RegisterDimensions(code,previnfo->fNext);
1874 fHasMultipleVarDim[code] = kTRUE;
1875 //previnfo = previnfo->fNext;
1876 leafinfo->fNext = new TFormLeafInfoCollection(elemCl,0,
1877 valueCl);
1878 elemCl = valueCl;
1879 }
1880 if (elemCl->GetCollectionProxy() &&
1881 elemCl->GetCollectionProxy()->GetValueClass()==0) {
1883 if (leafinfo->fNext) leafinfo->fNext->fNext = info;
1884 else leafinfo->fNext = info;
1885 }
1886 }
1887 } else if ( (object || pointer) && !useReferenceObject && element->GetClassPointer()->GetReferenceProxy() ) {
1888 TClass* c = element->GetClassPointer();
1889 R__LoadBranch(leaf->GetBranch(),readentry,fQuickLoad);
1890 if ( object ) {
1891 leafinfo = new TFormLeafInfoReference(c, element, offset);
1892 }
1893 else {
1894 leafinfo = new TFormLeafInfoPointer(cl,offset,element);
1895 leafinfo->fNext = new TFormLeafInfoReference(c, element, 0);
1896 }
1897 //if ( c->GetReferenceProxy()->HasCounter() ) {
1898 // numberOfVarDim += RegisterDimensions(code,-1);
1899 //}
1900 prevUseReferenceObject = kFALSE;
1901 needClass = kFALSE;
1902 mustderef = kTRUE;
1903 } else if (pointer) {
1904 // this is a pointer to be followed.
1905 leafinfo = new TFormLeafInfoPointer(cl,offset,element);
1906 mustderef = kTRUE;
1907 } else {
1908 // this is an embedded object.
1909 R__ASSERT(object);
1910 leafinfo = new TFormLeafInfo(cl,offset,element);
1911 }
1912 }
1913 }
1914 } else {
1915 if (cl) Error("DefinedVariable","%s is not a datamember of %s",work,cl->GetName());
1916 // no else, we warned earlier that the class was missing.
1917 return -1;
1918 }
1919
1920 numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,useCollectionObject); // Note or useCollectionObject||prevUseColectionObject
1921 if (maininfo==0) {
1922 maininfo = leafinfo;
1923 }
1924 if (previnfo==0) {
1925 previnfo = leafinfo;
1926 } else if (previnfo!=leafinfo) {
1927 previnfo->fNext = leafinfo;
1928 previnfo = leafinfo;
1929 }
1930 while (previnfo->fNext) previnfo = previnfo->fNext;
1931
1932 if ( right[i] != '\0' ) {
1933 if ( !needClass && mustderef ) {
1934 maininfo->SetBranch(leaf->GetBranch());
1935 char *ptr = (char*)maininfo->GetValuePointer(leaf,0);
1936 TFormLeafInfoReference* refInfo = 0;
1937 if ( !maininfo->IsReference() ) {
1938 for( TFormLeafInfo* inf = maininfo->fNext; inf; inf = inf->fNext ) {
1939 if ( inf->IsReference() ) {
1940 refInfo = (TFormLeafInfoReference*)inf;
1941 }
1942 }
1943 }
1944 else {
1945 refInfo = (TFormLeafInfoReference*)maininfo;
1946 }
1947 if ( refInfo ) {
1948 cl = refInfo->GetValueClass(ptr);
1949 if ( !cl ) {
1950 Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1951 return -1;
1952 }
1953 element = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1954 }
1955 else {
1956 Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1957 return -1;
1958 }
1959 }
1960 else if ( needClass ) {
1961 cl = element->GetClassPointer();
1962 }
1963 }
1964 if (mustderef) leafinfo = 0;
1965 current = &(work[0]);
1966 *current = 0;
1967 R__ASSERT(right[i] != '['); // We are supposed to have removed all dimensions already!
1968
1969 if (cl == TString::Class() && strcmp(right+i+1,"fData") == 0) {
1970 // For backward compatibility replace TString::fData which no longer exist
1971 // by a call to TString::Data()
1972 right = ".Data()";
1973 i = 0;
1974 nchname = strlen(right);
1975 }
1976
1977 } else
1978 *current++ = right[i];
1979 }
1980 if (maininfo) {
1981 fDataMembers.AddAtAndExpand(maininfo,code);
1982 if (leaf) fLookupType[code] = kDataMember;
1983 else fLookupType[code] = kTreeMember;
1984 }
1985 }
1986
1987 if (strlen(work)!=0) {
1988 // We have something left to analyze. Let's make this an error case!
1989 return -1;
1990 }
1991
1992 TClass *objClass = EvalClass(code);
1993 if (objClass && !useLeafCollectionObject && objClass->GetCollectionProxy() && objClass->GetCollectionProxy()->GetValueClass()) {
1994 TFormLeafInfo *last = 0;
1995 if ( SwitchToFormLeafInfo(code) ) {
1996
1997 last = (TFormLeafInfo*)fDataMembers.At(code);
1998
1999 if (!last) return action;
2000 while (last->fNext) { last = last->fNext; }
2001
2002 }
2003 if (last && last->GetClass() != objClass) {
2004 TClass *mother_cl;
2005 if (leaf->IsA()==TLeafObject::Class()) {
2006 // in this case mother_cl is not really used
2007 mother_cl = cl;
2008 } else {
2009 mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
2010 }
2011
2012 TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(mother_cl, 0, objClass, kFALSE);
2013 // The dimension needs to be handled!
2014 numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
2015 last->fNext = collectioninfo;
2016 }
2017 numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0
2018 objClass = objClass->GetCollectionProxy()->GetValueClass();
2019 }
2020 if (IsLeafString(code) || objClass == TString::Class() || objClass == stdStringClass) {
2021
2022 TFormLeafInfo *last = 0;
2023 if ( SwitchToFormLeafInfo(code) ) {
2024
2025 last = (TFormLeafInfo*)fDataMembers.At(code);
2026
2027 if (!last) return action;
2028 while (last->fNext) { last = last->fNext; }
2029
2030 }
2031 const char *funcname = 0;
2032 if (objClass == TString::Class()) {
2033 funcname = "Data";
2034 //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2035 } else if (objClass == stdStringClass) {
2036 funcname = "c_str";
2037 //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2038 }
2039 if (funcname) {
2040 TMethodCall *method = new TMethodCall(objClass, funcname, "");
2041 if (last) {
2042 last->fNext = new TFormLeafInfoMethod(objClass,method);
2043 } else {
2044 fDataMembers.AddAtAndExpand(new TFormLeafInfoMethod(objClass,method),code);
2045 if (leaf) fLookupType[code] = kDataMember;
2046 else fLookupType[code] = kTreeMember;
2047 }
2048 }
2049 return kDefinedString;
2050 }
2051
2052 if (objClass) {
2053 TMethodCall *method = new TMethodCall(objClass, "AsDouble", "");
2054 if (method->IsValid()
2055 && (method->ReturnType() == TMethodCall::kLong || method->ReturnType() == TMethodCall::kDouble)) {
2056
2057 TFormLeafInfo *last = 0;
2058 if (SwitchToFormLeafInfo(code)) {
2059 last = (TFormLeafInfo*)fDataMembers.At(code);
2060 // Improbable case
2061 if (!last) {
2062 delete method;
2063 return action;
2064 }
2065 while (last->fNext) { last = last->fNext; }
2066 }
2067 if (last) {
2068 last->fNext = new TFormLeafInfoMethod(objClass,method);
2069 } else {
2070 fDataMembers.AddAtAndExpand(new TFormLeafInfoMethod(objClass,method),code);
2071 if (leaf) fLookupType[code] = kDataMember;
2072 else fLookupType[code] = kTreeMember;
2073 }
2074
2075 return kDefinedVariable;
2076 }
2077 delete method;
2078 method = new TMethodCall(objClass, "AsString", "");
2079 if (method->IsValid()
2080 && method->ReturnType() == TMethodCall::kString) {
2081
2082 TFormLeafInfo *last = 0;
2083 if (SwitchToFormLeafInfo(code)) {
2084 last = (TFormLeafInfo*)fDataMembers.At(code);
2085 // Improbable case
2086 if (!last) {
2087 delete method;
2088 return action;
2089 }
2090 while (last->fNext) { last = last->fNext; }
2091 }
2092 if (last) {
2093 last->fNext = new TFormLeafInfoMethod(objClass,method);
2094 } else {
2095 fDataMembers.AddAtAndExpand(new TFormLeafInfoMethod(objClass,method),code);
2096 if (leaf) fLookupType[code] = kDataMember;
2097 else fLookupType[code] = kTreeMember;
2098 }
2099
2100 //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2101 return kDefinedString;
2102 }
2103 if (method->IsValid()
2104 && method->ReturnType() == TMethodCall::kOther) {
2105
2107 if ((rcl == TString::Class() || rcl == stdStringClass) ) {
2108
2109 TFormLeafInfo *last = 0;
2110 if (SwitchToFormLeafInfo(code)) {
2111 last = (TFormLeafInfo*)fDataMembers.At(code);
2112 // Improbable case
2113 if (!last) {
2114 delete method;
2115 return action;
2116 }
2117 while (last->fNext) { last = last->fNext; }
2118 }
2119 if (last) {
2120 last->fNext = new TFormLeafInfoMethod(objClass,method);
2121 last = last->fNext;
2122 } else {
2123 last = new TFormLeafInfoMethod(objClass,method);
2124 fDataMembers.AddAtAndExpand(last,code);
2125 if (leaf) fLookupType[code] = kDataMember;
2126 else fLookupType[code] = kTreeMember;
2127 }
2128
2129 objClass = rcl;
2130
2131 const char *funcname = 0;
2132 if (objClass == TString::Class()) {
2133 funcname = "Data";
2134 } else if (objClass == stdStringClass) {
2135 funcname = "c_str";
2136 }
2137 if (funcname) {
2138 method = new TMethodCall(objClass, funcname, "");
2139 last->fNext = new TFormLeafInfoMethod(objClass,method);
2140 }
2141 return kDefinedString;
2142 }
2143 }
2144 delete method;
2145 }
2146
2147 return action;
2148}
2149
2150////////////////////////////////////////////////////////////////////////////////
2151/// Look for the leaf corresponding to the start of expression.
2152/// It returns the corresponding leaf if any.
2153/// It also modify the following arguments:
2154///
2155/// - leftover: contain from expression that was not used to determine the leaf
2156/// - final:
2157/// * paran_level: number of un-matched open parenthesis
2158/// * cast_queue: list of cast to be done
2159/// * aliases: list of aliases used
2160/// - Return <0 in case of failure
2161///
2162/// - Return 0 if a leaf has been found
2163/// - Return 2 if info about the TTree itself has been requested.
2164
2165Int_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)
2166{
2167 // Later on we will need to read one entry, let's make sure
2168 // it is a real entry.
2169 if (fTree->GetTree()==0) {
2170 fTree->LoadTree(0);
2171 if (fTree->GetTree()==0) return -1;
2172 }
2173 Long64_t readentry = fTree->GetTree()->GetReadEntry();
2174 if (readentry < 0) readentry=0;
2175 const char *cname = expression;
2176 char first[kMaxLen]; first[0] = '\0';
2177 char second[kMaxLen*2]; second[0] = '\0';
2178 char right[kMaxLen*2]; right[0] = '\0';
2179 char work[kMaxLen]; work[0] = '\0';
2180 char left[kMaxLen]; left[0] = '\0';
2181 char scratch[kMaxLen*5];
2182 char scratch2[kMaxLen*5];
2183 std::string currentname;
2184 Int_t previousdot = 0;
2185 char *current;
2186 TLeaf *tmp_leaf=0;
2187 TBranch *branch=0, *tmp_branch=0;
2188 Int_t nchname = strlen(cname);
2189 Int_t i;
2190 Bool_t foundAtSign = kFALSE;
2191 Bool_t startWithParan = kFALSE;
2192
2193 for (i=0, current = &(work[0]); i<=nchname && !final;i++ ) {
2194 // We will treated the terminator as a token.
2195 *current++ = cname[i];
2196
2197 if (cname[i] == '(') {
2198 ++paran_level;
2199
2200 if (current==work+1) {
2201 // If the expression starts with a paranthesis, we are likely
2202 // to have a cast operator inside.
2203 startWithParan = kTRUE;
2204 current--;
2205 }
2206 continue;
2207 //i++;
2208 //while( cname[i]!=')' && cname[i] ) {
2209 // *current++ = cname[i++];
2210 //}
2211 //*current++ = cname[i];
2212 ////*current = 0;
2213 //continue;
2214 }
2215 if (cname[i] == ')') {
2216 if (paran_level==0) {
2217 Error("DefinedVariable","Unmatched paranthesis in %s",fullExpression);
2218 return -1;
2219 }
2220 paran_level--;
2221
2222 if (startWithParan) {
2223 startWithParan = kFALSE; // the next match wont be against the starting paranthesis.
2224
2225 // Let's see if work is a classname and thus we have a cast.
2226 *(--current) = 0;
2227 TString cast_name = gInterpreter->TypeName(work);
2228 TClass *cast_cl = TClass::GetClass(cast_name);
2229 if (cast_cl) {
2230 // We must have a cast
2231 castqueue.AddAtAndExpand(cast_cl,paran_level);
2232 current = &(work[0]);
2233 *current = 0;
2234 // Warning("DefinedVariable","Found cast to %s",cast_fullExpression);
2235 continue;
2236 } else if (gROOT->GetType(cast_name)) {
2237 // We reset work
2238 current = &(work[0]);
2239 *current = 0;
2240 Warning("DefinedVariable",
2241 "Casting to primary types like \"%s\" is not supported yet",cast_name.Data());
2242 continue;
2243 }
2244 *(current++)=')';
2245 }
2246
2247 *current='\0';
2248 char *params = strchr(work,'(');
2249 if (params) {
2250 *params = 0; params++;
2251
2252 if (branch && !leaf) {
2253 // We have a branch but not a leaf. We are likely to have found
2254 // the top of split branch.
2255 if (BranchHasMethod(0, branch, work, params, readentry)) {
2256 //fprintf(stderr, "Does have a method %s for %s.\n", work, branch->GetName());
2257 }
2258 }
2259
2260 // What we have so far might be a member function of one of the
2261 // leaves that are not split (for example "GetNtrack" for the Event class).
2263 TLeaf* leafcur = 0;
2264 while (!leaf && (leafcur = (TLeaf*) next())) {
2265 TBranch* br = leafcur->GetBranch();
2266 Bool_t yes = BranchHasMethod(leafcur, br, work, params, readentry);
2267 if (yes) {
2268 leaf = leafcur;
2269 //fprintf(stderr, "Does have a method %s for %s found in leafcur %s.\n", work, leafcur->GetBranch()->GetName(), leafcur->GetName());
2270 }
2271 }
2272 if (!leaf) {
2273 // Check for an alias.
2274 if (strlen(left) && left[strlen(left)-1]=='.') left[strlen(left)-1]=0;
2275 const char *aliasValue = fTree->GetAlias(left);
2276 if (aliasValue && strcspn(aliasValue,"+*/-%&!=<>|")==strlen(aliasValue)) {
2277 // First check whether we are using this alias recursively (this would
2278 // lead to an infinite recursion.
2279 if (find(aliasUsed.begin(),
2280 aliasUsed.end(),
2281 left) != aliasUsed.end()) {
2282 Error("DefinedVariable",
2283 "The substitution of the branch alias \"%s\" by \"%s\" in \"%s\" failed\n"\
2284 "\tbecause \"%s\" is used [recursively] in its own definition!",
2285 left,aliasValue,fullExpression,left);
2286 return -3;
2287 }
2288 aliasUsed.push_back(left);
2289 TString newExpression = aliasValue;
2290 newExpression += (cname+strlen(left));
2291 Int_t res = FindLeafForExpression(newExpression, leaf, leftover, final, paran_level,
2292 castqueue, aliasUsed, useLeafCollectionObject, fullExpression);
2293 if (res<0) {
2294 Error("DefinedVariable",
2295 "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue);
2296 return -3;
2297 }
2298 return res;
2299 }
2300
2301 // This is actually not really any error, we probably received something
2302 // like "abs(some_val)", let ROOT::v5::TFormula decompose it first.
2303 return -1;
2304 }
2305 // if (!leaf->InheritsFrom(TLeafObject::Class()) ) {
2306 // If the leaf that we found so far is not a TLeafObject then there is
2307 // nothing we would be able to do.
2308 // Error("DefinedVariable","Need a TLeafObject to call a function!");
2309 // return -1;
2310 //}
2311 // We need to recover the info not used.
2312 strlcpy(right,work,2*kMaxLen);
2313 strncat(right,"(",2*kMaxLen-1-strlen(right));
2314 strncat(right,params,2*kMaxLen-1-strlen(right));
2315 final = kTRUE;
2316
2317 // Record in 'i' what we consumed
2318 i += strlen(params);
2319
2320 // we reset work
2321 current = &(work[0]);
2322 *current = 0;
2323 break;
2324 }
2325 }
2326 if (cname[i] == '.' || cname[i] == '\0' || cname[i] == ')') {
2327 // A delimiter happened let's see if what we have seen
2328 // so far does point to a leaf.
2329 *current = '\0';
2330
2331 Int_t len = strlen(work);
2332 if (work[0]=='@') {
2333 foundAtSign = kTRUE;
2334 Int_t l = 0;
2335 for(l=0;work[l+1]!=0;++l) work[l] = work[l+1];
2336 work[l] = '\0';
2337 --current;
2338 } else if (len>=2 && work[len-2]=='@') {
2339 foundAtSign = kTRUE;
2340 work[len-2] = cname[i];
2341 work[len-1] = '\0';
2342 --current;
2343 } else {
2344 foundAtSign = kFALSE;
2345 }
2346
2347 if (left[0]==0) strlcpy(left,work,kMaxLen);
2348 if (!leaf && !branch) {
2349 // So far, we have not found a matching leaf or branch.
2350 strlcpy(first,work,kMaxLen);
2351
2352 std::string treename(first);
2353 if (treename.size() && treename[treename.size()-1]=='.') {
2354 treename.erase(treename.size()-1);
2355 }
2356 if (treename== "This" /* || treename == fTree->GetName() */ ) {
2357 // Request info about the TTree object itself,
2358 TNamed *named = new TNamed(fTree->GetName(),fTree->GetName());
2361 if (cname[i]) leftover = &(cname[i+1]);
2362 return 2;
2363 }
2364 // The following would allow to access the friend by name
2365 // however, it would also prevent the access of the leaves
2366 // within the friend. We could use the '@' notation here
2367 // however this would not be aesthetically pleasing :(
2368 // What we need to do, is add the ability to look ahead to
2369 // the next 'token' to decide whether we to access the tree
2370 // or its leaf.
2371 //} else {
2372 // TTree *tfriend = fTree->GetFriend(treename.c_str());
2373 // TTree *realtree = fTree->GetTree();
2374 // if (!tfriend && realtree != fTree){
2375 // // If it is a chain and we did not find a friend,
2376 // // let's try with the internal tree.
2377 // tfriend = realtree->GetFriend(treename.c_str());
2378 // }
2379 // if (tfriend) {
2380 // TNamed *named = new TNamed(treename.c_str(),tfriend->GetName());
2381 // fLeafNames.AddAtAndExpand(named,fNcodes);
2382 // fLeaves.AddAtAndExpand(tfriend,fNcodes);
2383 // if (cname[i]) leftover = &(cname[i+1]);
2384 // return 2;
2385 // }
2386 //}
2387
2388 branch = fTree->FindBranch(first);
2389 leaf = fTree->FindLeaf(first);
2390
2391 // Now look with the delimiter removed (we looked with it first
2392 // because a dot is allowed at the end of some branches).
2393 if (cname[i]) first[strlen(first)-1]='\0';
2394 if (!branch) branch = fTree->FindBranch(first);
2395 if (!leaf) leaf = fTree->FindLeaf(first);
2396 TClass* cl = 0;
2397 if ( branch && branch->InheritsFrom(TBranchElement::Class()) ) {
2398 int offset=0;
2399 TBranchElement* bElt = (TBranchElement*)branch;
2400 TStreamerInfo* info = bElt->GetInfo();
2401 TStreamerElement* element = info ? info->GetStreamerElement(first,offset) : 0;
2402 if (element) cl = element->GetClassPointer();
2403 if ( cl && !cl->GetReferenceProxy() ) cl = 0;
2404 }
2405 if ( cl ) { // We have a reference class here....
2406 final = kTRUE;
2407 useLeafCollectionObject = foundAtSign;
2408 // we reset work
2409 current = &(work[0]);
2410 *current = 0;
2411 }
2412 else if (branch && (foundAtSign || cname[i] != 0) ) {
2413 // Since we found a branch and there is more information in the name,
2414 // we do NOT look at the 'IsOnTerminalBranch' status of the leaf
2415 // we found ... yet!
2416
2417 if (leaf==0) {
2418 // Note we do not know (yet?) what (if anything) to do
2419 // for a TBranchObject branch.
2420 if (branch->InheritsFrom(TBranchElement::Class()) ) {
2421 Int_t type = ((TBranchElement*)branch)->GetType();
2422 if ( type == 3 || type ==4) {
2423 // We have a Collection branch.
2424 leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
2425 if (foundAtSign) {
2426 useLeafCollectionObject = foundAtSign;
2427 foundAtSign = kFALSE;
2428 current = &(work[0]);
2429 *current = 0;
2430 ++i;
2431 break;
2432 }
2433 }
2434 }
2435 }
2436
2437 // we reset work
2438 useLeafCollectionObject = foundAtSign;
2439 foundAtSign = kFALSE;
2440 current = &(work[0]);
2441 *current = 0;
2442 } else if (leaf || branch) {
2443 if (leaf && branch) {
2444 // We found both a leaf and branch matching the request name
2445 // let's see which one is the proper one to use! (On annoying case
2446 // is that where the same name is repeated ( varname.varname )
2447
2448 // We always give priority to the branch
2449 // leaf = 0;
2450 }
2451 if (leaf && leaf->IsOnTerminalBranch()) {
2452 // This is a non-object leaf, it should NOT be specified more except for
2453 // dimensions.
2454 final = kTRUE;
2455 }
2456 // we reset work
2457 current = &(work[0]);
2458 *current = 0;
2459 } else {
2460 // What we have so far might be a data member of one of the
2461 // leaves that are not split (for example "fNtrack" for the Event class.
2462 TLeaf *leafcur = GetLeafWithDatamember(first,work,readentry);
2463 if (leafcur) {
2464 leaf = leafcur;
2465 branch = leaf->GetBranch();
2466 if (leaf->IsOnTerminalBranch()) {
2467 final = kTRUE;
2468 strlcpy(right,first,kMaxLen);
2469 //We need to put the delimiter back!
2470 if (foundAtSign) strncat(right,"@",2*kMaxLen-1-strlen(right));
2471 if (cname[i]=='.') strncat(right,".",2*kMaxLen-1-strlen(right));
2472
2473 // We reset work
2474 current = &(work[0]);
2475 *current = 0;
2476 };
2477 } else if (cname[i] == '.') {
2478 // If we have a branch that match a name preceded by a dot
2479 // then we assume we are trying to drill down the branch
2480 // Let look if one of the top level branch has a branch with the name
2481 // we are looking for.
2482 TBranch *branchcur;
2483 TIter next( fTree->GetListOfBranches() );
2484 while(!branch && (branchcur=(TBranch*)next()) ) {
2485 branch = branchcur->FindBranch(first);
2486 }
2487 if (branch) {
2488 // We reset work
2489 current = &(work[0]);
2490 *current = 0;
2491 }
2492 }
2493 }
2494 } else { // correspond to if (leaf || branch)
2495 if (final) {
2496 Error("DefinedVariable", "Unexpected control flow!");
2497 return -1;
2498 }
2499
2500 // No dot is allowed in subbranches and leaves, so
2501 // we always remove it in the present case.
2502 if (cname[i]) work[strlen(work)-1] = '\0';
2503 snprintf(scratch,sizeof(scratch),"%s.%s",first,work);
2504 snprintf(scratch2,sizeof(scratch2),"%s.%s.%s",first,second,work);
2505
2506 if (previousdot) {
2507 currentname = &(work[previousdot+1]);
2508 }
2509
2510 // First look for the current 'word' in the list of
2511 // leaf of the
2512 if (branch) {
2513 tmp_leaf = branch->FindLeaf(work);
2514 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch);
2515 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch2);
2516 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(currentname.c_str());
2517 }
2518 if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
2519 // This is a non-object leaf, it should NOT be specified more except for
2520 // dimensions.
2521 final = kTRUE;
2522 }
2523
2524 if (branch) {
2525 tmp_branch = branch->FindBranch(work);
2526 if (!tmp_branch) tmp_branch = branch->FindBranch(scratch);
2527 if (!tmp_branch) tmp_branch = branch->FindBranch(scratch2);
2528 if (!tmp_branch) tmp_branch = branch->FindBranch(currentname.c_str());
2529 }
2530 if (tmp_branch) {
2531 branch=tmp_branch;
2532
2533 // NOTE: Should we look for a leaf within here?
2534 if (!final) {
2535 tmp_leaf = branch->FindLeaf(work);
2536 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch);
2537 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch2);
2538 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(currentname.c_str());
2539 if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
2540 // This is a non-object leaf, it should NOT be specified
2541 // more except for dimensions.
2542 final = kTRUE;
2543 leaf = tmp_leaf;
2544 }
2545 }
2546 }
2547 if (tmp_leaf) {
2548 // Something was found.
2549 if (second[0]) strncat(second,".",2*kMaxLen-1-strlen(second));
2550 strncat(second,work,2*kMaxLen-1-strlen(second));
2551 leaf = tmp_leaf;
2552 useLeafCollectionObject = foundAtSign;
2553 foundAtSign = kFALSE;
2554
2555 // we reset work
2556 current = &(work[0]);
2557 *current = 0;
2558 } else {
2559 //We need to put the delimiter back!
2560 if (strlen(work)) {
2561 if (foundAtSign) {
2562 Int_t where = strlen(work);
2563 work[where] = '@';
2564 work[where+1] = cname[i];
2565 ++current;
2566 previousdot = where+1;
2567 } else {
2568 previousdot = strlen(work);
2569 work[strlen(work)] = cname[i];
2570 }
2571 } else --current;
2572 }
2573 }
2574 }
2575 }
2576
2577 // Copy the left over for later use.
2578 if (strlen(work)) {
2579 strncat(right,work,2*kMaxLen-1-strlen(right));
2580 }
2581
2582 if (i<nchname) {
2583 if (strlen(right) && right[strlen(right)-1]!='.' && cname[i]!='.') {
2584 // In some cases we remove a little to fast the period, we add
2585 // it back if we need. It is assumed that 'right' and the rest of
2586 // the name was cut by a delimiter, so this should be safe.
2587 strncat(right,".",2*kMaxLen-1-strlen(right));
2588 }
2589 strncat(right,&cname[i],2*kMaxLen-1-strlen(right));
2590 }
2591
2592 if (!final && branch) {
2593 if (!leaf) {
2594 leaf = (TLeaf*)branch->GetListOfLeaves()->UncheckedAt(0);
2595 if (!leaf) return -1;
2596 }
2597 final = leaf->IsOnTerminalBranch();
2598 }
2599
2600 if (leaf && leaf->InheritsFrom(TLeafObject::Class()) ) {
2601 if (strlen(right)==0) strlcpy(right,work,2*kMaxLen);
2602 }
2603
2604 if (leaf==0 && left[0]!=0) {
2605 if (left[strlen(left)-1]=='.') left[strlen(left)-1]=0;
2606
2607 // Check for an alias.
2608 const char *aliasValue = fTree->GetAlias(left);
2609 if (aliasValue && strcspn(aliasValue,"()[]+*/-%&!=<>|")==strlen(aliasValue)) {
2610 // First check whether we are using this alias recursively (this would
2611 // lead to an infinite recursion).
2612 if (find(aliasUsed.begin(),
2613 aliasUsed.end(),
2614 left) != aliasUsed.end()) {
2615 Error("DefinedVariable",
2616 "The substitution of the branch alias \"%s\" by \"%s\" in \"%s\" failed\n"\
2617 "\tbecause \"%s\" is used [recursively] in its own definition!",
2618 left,aliasValue,fullExpression,left);
2619 return -3;
2620 }
2621 aliasUsed.push_back(left);
2622 TString newExpression = aliasValue;
2623 newExpression += (cname+strlen(left));
2624 Int_t res = FindLeafForExpression(newExpression, leaf, leftover, final, paran_level,
2625 castqueue, aliasUsed, useLeafCollectionObject, fullExpression);
2626 if (res<0) {
2627 Error("DefinedVariable",
2628 "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue);
2629 return -3;
2630 }
2631 return res;
2632 }
2633 }
2634 leftover = right;
2635
2636 return 0;
2637}
2638
2639////////////////////////////////////////////////////////////////////////////////
2640/// Check if name is in the list of Tree/Branch leaves.
2641///
2642/// This member function redefines the function in ROOT::v5::TFormula
2643/// If a leaf has a name corresponding to the argument name, then
2644/// returns a new code.
2645///
2646/// A TTreeFormula may contain more than one variable.
2647/// For each variable referenced, the pointers to the corresponding
2648/// branch and leaf is stored in the object arrays fBranches and fLeaves.
2649///
2650/// name can be :
2651/// - Leaf_Name (simple variable or data member of a ClonesArray)
2652/// - Branch_Name.Leaf_Name
2653/// - Branch_Name.Method_Name
2654/// - Leaf_Name[index]
2655/// - Branch_Name.Leaf_Name[index]
2656/// - Branch_Name.Leaf_Name[index1]
2657/// - Branch_Name.Leaf_Name[][index2]
2658/// - Branch_Name.Leaf_Name[index1][index2]
2659///
2660/// New additions:
2661/// - Branch_Name.Leaf_Name[OtherLeaf_Name]
2662/// - Branch_Name.Datamember_Name
2663/// - '.' can be replaced by '->'
2664///
2665/// and
2666/// - Branch_Name[index1].Leaf_Name[index2]
2667/// - Leaf_name[index].Action().OtherAction(param)
2668/// - Leaf_name[index].Action()[val].OtherAction(param)
2669///
2670/// The expected returns values are
2671/// - -2 : the name has been recognized but won't be usable
2672/// - -1 : the name has not been recognized
2673/// - >=0 : the name has been recognized, return the internal code for this name.
2674
2676{
2677
2678 action = kDefinedVariable;
2679 if (!fTree) return -1;
2680
2681 fNpar = 0;
2682 if (name.Length() > kMaxLen) return -1;
2683 Int_t i,k;
2684
2685 if (name == "Entry$") {
2686 Int_t code = fNcodes++;
2687 fCodes[code] = 0;
2688 fLookupType[code] = kIndexOfEntry;
2689 return code;
2690 }
2691 if (name == "LocalEntry$") {
2692 Int_t code = fNcodes++;
2693 fCodes[code] = 0;
2695 return code;
2696 }
2697 if (name == "Entries$") {
2698 Int_t code = fNcodes++;
2699 fCodes[code] = 0;
2700 fLookupType[code] = kEntries;
2703 return code;
2704 }
2705 if (name == "LocalEntries$") {
2706 Int_t code = fNcodes++;
2707 fCodes[code] = 0;
2708 fLookupType[code] = kLocalEntries;
2709 SetBit(kNeedEntries); // FIXME: necessary?
2710 fManager->SetBit(kNeedEntries); // FIXME: necessary?
2711 return code;
2712 }
2713 if (name == "Iteration$") {
2714 Int_t code = fNcodes++;
2715 fCodes[code] = 0;
2716 fLookupType[code] = kIteration;
2717 return code;
2718 }
2719 if (name == "Length$") {
2720 Int_t code = fNcodes++;
2721 fCodes[code] = 0;
2722 fLookupType[code] = kLength;
2723 return code;
2724 }
2725 static const char *lenfunc = "Length$(";
2726 if (strncmp(name.Data(),"Length$(",strlen(lenfunc))==0
2727 && name[name.Length()-1]==')') {
2728
2729 TString subform = name.Data()+strlen(lenfunc);
2730 subform.Remove( subform.Length() - 1 );
2731 TTreeFormula *lengthForm = new TTreeFormula("lengthForm",subform,fTree);
2732 fAliases.AddAtAndExpand(lengthForm,fNoper);
2733 Int_t code = fNcodes++;
2734 fCodes[code] = 0;
2735 fLookupType[code] = kLengthFunc;
2736 return code;
2737 }
2738 static const char *minfunc = "Min$(";
2739 if (strncmp(name.Data(),"Min$(",strlen(minfunc))==0
2740 && name[name.Length()-1]==')') {
2741
2742 TString subform = name.Data()+strlen(minfunc);
2743 subform.Remove( subform.Length() - 1 );
2744 TTreeFormula *minForm = new TTreeFormula("minForm",subform,fTree);
2746 Int_t code = fNcodes++;
2747 fCodes[code] = 0;
2748 fLookupType[code] = kMin;
2749 return code;
2750 }
2751 static const char *maxfunc = "Max$(";
2752 if (strncmp(name.Data(),"Max$(",strlen(maxfunc))==0
2753 && name[name.Length()-1]==')') {
2754
2755 TString subform = name.Data()+strlen(maxfunc);
2756 subform.Remove( subform.Length() - 1 );
2757 TTreeFormula *maxForm = new TTreeFormula("maxForm",subform,fTree);
2759 Int_t code = fNcodes++;
2760 fCodes[code] = 0;
2761 fLookupType[code] = kMax;
2762 return code;
2763 }
2764 static const char *sumfunc = "Sum$(";
2765 if (strncmp(name.Data(),"Sum$(",strlen(sumfunc))==0
2766 && name[name.Length()-1]==')') {
2767
2768 TString subform = name.Data()+strlen(sumfunc);
2769 subform.Remove( subform.Length() - 1 );
2770 TTreeFormula *sumForm = new TTreeFormula("sumForm",subform,fTree);
2772 Int_t code = fNcodes++;
2773 fCodes[code] = 0;
2774 fLookupType[code] = kSum;
2775 return code;
2776 }
2777
2778
2779
2780 // Check for $Alt(expression1,expression2)
2781 Int_t res = DefineAlternate(name.Data());
2782 if (res!=0) {
2783 // There was either a syntax error or we found $Alt
2784 if (res<0) return res;
2785 action = res;
2786 return 0;
2787 }
2788
2789 // Find the top level leaf and deal with dimensions
2790
2791 char cname[kMaxLen]; strlcpy(cname,name.Data(),kMaxLen);
2792 char dims[kMaxLen]; dims[0] = '\0';
2793
2794 Bool_t final = kFALSE;
2795
2796 UInt_t paran_level = 0;
2797 TObjArray castqueue;
2798
2799 // First, it is easier to remove all dimensions information from 'cname'
2800 Int_t cnamelen = strlen(cname);
2801 for(i=0,k=0; i<cnamelen; ++i, ++k) {
2802 if (cname[i] == '[') {
2803 int bracket = i;
2804 int bracket_level = 1;
2805 int j;
2806 for (j=++i; j<cnamelen && (bracket_level>0 || cname[j]=='['); j++, i++) {
2807 if (cname[j]=='[') bracket_level++;
2808 else if (cname[j]==']') bracket_level--;
2809 }
2810 if (bracket_level != 0) {
2811 //Error("DefinedVariable","Bracket unbalanced");
2812 return -1;
2813 }
2814 strncat(dims,&cname[bracket],j-bracket);
2815 //k += j-bracket;
2816 }
2817 if (i!=k) cname[k] = cname[i];
2818 }
2819 cname[k]='\0';
2820
2821 Bool_t useLeafCollectionObject = kFALSE;
2822 TString leftover;
2823 TLeaf *leaf = 0;
2824 {
2825 std::vector<std::string> aliasSofar = fAliasesUsed;
2826 res = FindLeafForExpression(cname, leaf, leftover, final, paran_level, castqueue, aliasSofar, useLeafCollectionObject, name);
2827 }
2828 if (res<0) return res;
2829
2830 if (!leaf && res!=2) {
2831 // Check for an alias.
2832 const char *aliasValue = fTree->GetAlias(cname);
2833 if (aliasValue) {
2834 // First check whether we are using this alias recursively (this would
2835 // lead to an infinite recursion.
2836 if (find(fAliasesUsed.begin(),
2837 fAliasesUsed.end(),
2838 cname) != fAliasesUsed.end()) {
2839 Error("DefinedVariable",
2840 "The substitution of the alias \"%s\" by \"%s\" failed\n"\
2841 "\tbecause \"%s\" is recursively used in its own definition!",
2842 cname,aliasValue,cname);
2843 return -3;
2844 }
2845
2846
2847 if (strcspn(aliasValue,"()+*/-%&!=<>|")!=strlen(aliasValue)) {
2848 // If the alias contains an operator, we need to use a nested formula
2849 // (since DefinedVariable must only add one entry to the operation's list).
2850
2851 // Need to check the aliases used so far
2852 std::vector<std::string> aliasSofar = fAliasesUsed;
2853 aliasSofar.push_back( cname );
2854
2855 TString subValue( aliasValue );
2856 if (dims[0]) {
2857 subValue += dims;
2858 }
2859
2860 TTreeFormula *subform = new TTreeFormula(cname,subValue,fTree,aliasSofar); // Need to pass the aliases used so far.
2861
2862 if (subform->GetNdim()==0) {
2863 delete subform;
2864 Error("DefinedVariable",
2865 "The substitution of the alias \"%s\" by \"%s\" failed.",cname,aliasValue);
2866 return -3;
2867 }
2868
2869 fManager->Add(subform);
2871
2872 if (subform->IsString()) {
2873 action = kAliasString;
2874 return 0;
2875 } else {
2876 action = kAlias;
2877 return 0;
2878 }
2879 } else { /* assumes strcspn(aliasValue,"[]")!=strlen(aliasValue) */
2880 TString thisAlias( aliasValue );
2881 thisAlias += dims;
2882 Int_t aliasRes = DefinedVariable(thisAlias,action);
2883 if (aliasRes<0) {
2884 // We failed but DefinedVariable has not printed why yet.
2885 // and because we want thoses to be printed _before_ the notice
2886 // of the failure of the substitution, we need to print them here.
2887 if (aliasRes==-1) {
2888 Error("Compile", " Bad numerical expression : \"%s\"",thisAlias.Data());
2889 } else if (aliasRes==-2) {
2890 Error("Compile", " Part of the Variable \"%s\" exists but some of it is not accessible or useable",thisAlias.Data());
2891
2892 }
2893 Error("DefinedVariable",
2894 "The substitution of the alias \"%s\" by \"%s\" failed.",cname,aliasValue);
2895 return -3;
2896 }
2897 return aliasRes;
2898 }
2899 }
2900 }
2901
2902
2903 if (leaf || res==2) {
2904
2905 if (leaf && leaf->GetBranch() && leaf->GetBranch()->TestBit(kDoNotProcess)) {
2906 Error("DefinedVariable","the branch \"%s\" has to be enabled to be used",leaf->GetBranch()->GetName());
2907 return -2;
2908 }
2909
2910 Int_t code = fNcodes++;
2911
2912 // If needed will now parse the indexes specified for
2913 // arrays.
2914 if (dims[0]) {
2915 char *current = &( dims[0] );
2916 Int_t dim = 0;
2917 TString varindex;
2918 Int_t index;
2919 Int_t scanindex ;
2920 while (current) {
2921 current++;
2922 if (current[0] == ']') {
2923 fIndexes[code][dim] = -1; // Loop over all elements;
2924 } else {
2925 scanindex = sscanf(current,"%d",&index);
2926 if (scanindex) {
2927 fIndexes[code][dim] = index;
2928 } else {
2929 fIndexes[code][dim] = -2; // Index is calculated via a variable.
2930 varindex = current;
2931 char *end = (char*)(varindex.Data());
2932 for(char bracket_level = 0;*end!=0;end++) {
2933 if (*end=='[') bracket_level++;
2934 if (bracket_level==0 && *end==']') break;
2935 if (*end==']') bracket_level--;
2936 }
2937 *end = '\0';
2938 fVarIndexes[code][dim] = new TTreeFormula("index_var",
2939 varindex,
2940 fTree);
2941 if (fVarIndexes[code][dim]->GetNdim() == 0) {
2942 // Parsing failed for the index, let's stop here ....
2943 return -1;
2944 }
2945 current += strlen(varindex)+1; // move to the end of the index array
2946 }
2947 }
2948 dim ++;
2949 if (dim >= kMAXFORMDIM) {
2950 // NOTE: test that dim this is NOT too big!!
2951 break;
2952 }
2953 current = (char*)strstr( current, "[" );
2954 }
2955 }
2956
2957 // Now that we have cleaned-up the expression, let's compare it to the content
2958 // of the leaf!
2959
2960 res = ParseWithLeaf(leaf,leftover,final,paran_level,castqueue,useLeafCollectionObject,name);
2961 if (res<0) return res;
2962 if (res>0) action = res;
2963 return code;
2964 }
2965
2966//*-*- May be a graphical cut ?
2967 TCutG *gcut = (TCutG*)gROOT->GetListOfSpecials()->FindObject(name.Data());
2968 if (gcut) {
2969 if (gcut->GetObjectX()) {
2971 delete gcut->GetObjectX(); gcut->SetObjectX(0);
2972 }
2973 }
2974 if (gcut->GetObjectY()) {
2976 delete gcut->GetObjectY(); gcut->SetObjectY(0);
2977 }
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:
3402 if (fDidBooleanOptimization && instance!=0) {
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: {
3416 if (instance <= fRealInstanceCache.fInstanceCache) {
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
3635void* TTreeFormula::EvalObject(int instance)
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;
5017 Int_t instance;
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 Int_t index;
5568 TFormLeafInfo * info = 0;
5569 if (fLookupType[i]!=kDirect) {
5570 info = (TFormLeafInfo *)fDataMembers.At(i);
5571 }
5572 for(Int_t k=0, virt_dim=0; k < fNdimensions[i]; k++) {
5573 if (fIndexes[i][k]<0) {
5574 if (fIndexes[i][k]==-2 && fManager->fVirtUsedSizes[virt_dim]<0) {
5575
5576 // if fVirtUsedSize[virt_dim] is positive then VarIndexes[i][k]->GetNdata()
5577 // is always the same and has already been factored in fUsedSize[virt_dim]
5578 index = fVarIndexes[i][k]->GetNdata();
5579 if (index==1) {
5580 // We could either have a variable size array which is currently of size one
5581 // or a single element that might or not might not be present (and is currently present!)
5582 if (fVarIndexes[i][k]->GetManager()->GetMultiplicity()==1) {
5583 if (index<fManager->fUsedSizes[virt_dim]) fManager->fUsedSizes[virt_dim] = index;
5584 }
5585
5586 } else if (fManager->fUsedSizes[virt_dim]==-fManager->fVirtUsedSizes[virt_dim] ||
5587 index<fManager->fUsedSizes[virt_dim]) {
5588 fManager->fUsedSizes[virt_dim] = index;
5589 }
5590
5591 } else if (hasBranchCount2 && info && k==info->GetVarDim()) {
5592 // NOTE: We assume the indexing of variable sizes on the first index!
5593 if (fIndexes[i][0]>=0) {
5594 index = info->GetSize(fIndexes[i][0]);
5595 if (fManager->fUsedSizes[virt_dim]==1 || (index!=1 && index<fManager->fUsedSizes[virt_dim]) )
5596 fManager->fUsedSizes[virt_dim] = index;
5597 }
5598 }
5599 virt_dim++;
5600 } else if (hasBranchCount2 && info && k==info->GetVarDim()) {
5601
5602 // nothing to do, at some point I thought this might be useful:
5603 // if (fIndexes[i][k]>=0) {
5604 // index = info->GetSize(fIndexes[i][k]);
5605 // if (fManager->fUsedSizes[virt_dim]==1 || (index!=1 && index<fManager->fUsedSizes[virt_dim]) )
5606 // fManager->fUsedSizes[virt_dim] = index;
5607 // virt_dim++;
5608 // }
5609
5610 }
5611 }
5612 }
5613 return ! outofbounds;
5614
5615
5616
5617}
5618
5619void TTreeFormula::Convert(UInt_t oldversion)
5620{
5621 // Convert the fOper of a TTTreeFormula version fromVersion to the current in memory version
5622
5623 enum { kOldAlias = /*ROOT::v5::TFormula::kVariable*/ 100000+10000+1,
5624 kOldAliasString = kOldAlias+1,
5625 kOldAlternate = kOldAlias+2,
5626 kOldAlternateString = kOldAliasString+2
5627 };
5628
5629 for (int k=0; k<fNoper; k++) {
5630 // First hide from ROOT::v5::TFormula convertion
5631
5632 Int_t action = GetOper()[k];
5633
5634 switch (action) {
5635
5636 case kOldAlias: GetOper()[k] = -kOldAlias; break;
5637 case kOldAliasString: GetOper()[k] = -kOldAliasString; break;
5638 case kOldAlternate: GetOper()[k] = -kOldAlternate; break;
5639 case kOldAlternateString: GetOper()[k] = -kOldAlternateString; break;
5640 }
5641 }
5642
5643 ROOT::v5::TFormula::Convert(oldversion);
5644
5645 for (int i=0,offset=0; i<fNoper; i++) {
5646 Int_t action = GetOper()[i+offset];
5647
5648 switch (action) {
5649 case -kOldAlias: SetAction(i, kAlias, 0); break;
5650 case -kOldAliasString: SetAction(i, kAliasString, 0); break;
5651 case -kOldAlternate: SetAction(i, kAlternate, 0); break;
5652 case -kOldAlternateString: SetAction(i, kAlternateString, 0); break;
5653 }
5654 }
5655
5656}
5657
5658////////////////////////////////////////////////////////////////////////////////
5659/// Convert the underlying lookup method from the direct technique
5660/// (dereferencing the address held by the branch) to the method using
5661/// TFormLeafInfo. This is in particular usefull in the case where we
5662/// need to append an additional TFormLeafInfo (for example to call a
5663/// method).
5664/// Return false if the switch was unsuccessfull (basically in the
5665/// case of an old style split tree).
5666
5668{
5669 TFormLeafInfo *last = 0;
5670 TLeaf *leaf = (TLeaf*)fLeaves.At(code);
5671 if (!leaf) return kFALSE;
5672
5673 if (fLookupType[code]==kDirect) {
5674 if (leaf->InheritsFrom(TLeafElement::Class())) {
5675 TBranchElement * br = (TBranchElement*)leaf->GetBranch();
5676 if (br->GetType()==31) {
5677 // sub branch of a TClonesArray
5678 TStreamerInfo *info = br->GetInfo();
5679 TClass* cl = info->GetClass();
5680 TStreamerElement *element = (TStreamerElement *)info->GetElement(br->GetID());
5681 TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(cl, 0, element, kTRUE);
5682 Int_t offset;
5683 info->GetStreamerElement(element->GetName(),offset);
5684 clonesinfo->fNext = new TFormLeafInfo(cl,offset+br->GetOffset(),element);
5685 last = clonesinfo->fNext;
5686 fDataMembers.AddAtAndExpand(clonesinfo,code);
5688
5689 } else if (br->GetType()==41) {
5690 // sub branch of a Collection
5691
5692 TBranchElement *count = br->GetBranchCount();
5693 TFormLeafInfo* collectioninfo;
5694 if ( count->GetID() >= 0 ) {
5695 TStreamerElement *collectionElement =
5696 (TStreamerElement *)count->GetInfo()->GetElement(count->GetID());
5697 TClass *collectionCl = collectionElement->GetClassPointer();
5698
5699 collectioninfo =
5700 new TFormLeafInfoCollection(collectionCl, 0, collectionElement, kTRUE);
5701 } else {
5702 TClass *collectionCl = TClass::GetClass(count->GetClassName());
5703 collectioninfo =
5704 new TFormLeafInfoCollection(collectionCl, 0, collectionCl, kTRUE);
5705 }
5706
5707 TStreamerInfo *info = br->GetInfo();
5708 TClass* cl = info->GetClass();
5709 TStreamerElement *element = (TStreamerElement *)info->GetElement(br->GetID());
5710 Int_t offset;
5711 info->GetStreamerElement(element->GetName(),offset);
5712 collectioninfo->fNext = new TFormLeafInfo(cl,offset+br->GetOffset(),element);
5713 last = collectioninfo->fNext;
5714 fDataMembers.AddAtAndExpand(collectioninfo,code);
5716
5717 } else if (br->GetID()<0) {
5718 return kFALSE;
5719 } else {
5720 last = new TFormLeafInfoDirect(br);
5721 fDataMembers.AddAtAndExpand(last,code);
5723 }
5724 } else {
5725 //last = new TFormLeafInfoDirect(br);
5726 //fDataMembers.AddAtAndExpand(last,code);
5727 //fLookupType[code]=kDataMember;
5728 return kFALSE;
5729 }
5730 }
5731 return kTRUE;
5732}
void Class()
Definition: Class.C:29
ROOT::R::TRInterface & r
Definition: Object.C:4
#define lenfunc
Definition: PyROOT.h:175
#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:36
int Int_t
Definition: RtypesCore.h:41
short Version_t
Definition: RtypesCore.h:61
int Ssiz_t
Definition: RtypesCore.h:63
char Char_t
Definition: RtypesCore.h:29
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
unsigned long ULong_t
Definition: RtypesCore.h:51
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
short Short_t
Definition: RtypesCore.h:35
double Double_t
Definition: RtypesCore.h:55
long double LongDouble_t
Definition: RtypesCore.h:57
long long Long64_t
Definition: RtypesCore.h:69
unsigned long long ULong64_t
Definition: RtypesCore.h:70
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define ClassImp(name)
Definition: Rtypes.h:363
const Int_t kDoNotProcess
Definition: TBranch.h:52
@ kChar_t
Definition: TDataType.h:29
#define gDirectory
Definition: TDirectory.h:213
#define R__ASSERT(e)
Definition: TError.h:96
int type
Definition: TGX11.cxx:120
#define gInterpreter
Definition: TInterpreter.h:538
#define gROOT
Definition: TROOT.h:410
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:279
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:64
virtual char * GetAddress() const
Definition: TBranch.h:171
TTree * GetTree() const
Definition: TBranch.h:209
TObjArray * GetListOfBranches()
Definition: TBranch.h:203
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:1317
Int_t GetOffset() const
Definition: TBranch.h:192
virtual TLeaf * FindLeaf(const char *name)
Find the leaf corresponding to the name 'searchname'.
Definition: TBranch.cxx:1042
Long64_t GetReadEntry() const
Definition: TBranch.h:194
virtual void Print(Option_t *option="") const
Print TBranch parameters.
Definition: TBranch.cxx:1924
virtual void ResetReadEntry()
Definition: TBranch.h:226
virtual TBranch * FindBranch(const char *name)
Find the immediate sub-branch with passed name.
Definition: TBranch.cxx:996
TObjArray * GetListOfLeaves()
Definition: TBranch.h:204
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition: TBranch.cxx:1725
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
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:83
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:29
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition: TClass.cxx:4452
Bool_t HasDataMemberInfo() const
Definition: TClass.h:378
ClassInfo_t * GetClassInfo() const
Definition: TClass.h:404
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2814
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition: TClass.cxx:4237
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4720
TVirtualRefProxy * GetReferenceProxy() const
Definition: TClass.h:453
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:2885
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:393
TObject * GetObjectY() const
Definition: TCutG.h:40
virtual void SetObjectX(TObject *obj)
Set the X object (and delete the previous one if any).
Definition: TCutG.cxx:384
TObject * GetObjectX() const
Definition: TCutG.h:39
const char * GetVarY() const
Definition: TCutG.h:42
Describe directory structure in memory.
Definition: TDirectory.h:34
virtual Bool_t cd(const char *path=0)
Change current directory to "this" directory.
Definition: TDirectory.cxx:497
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:517
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:1825
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:30
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:32
virtual void * GetValuePointer() const
Definition: TLeaf.h:92
virtual Bool_t IsOnTerminalBranch() const
Definition: TLeaf.h:102
virtual const char * GetTypeName() const
Definition: TLeaf.h:93
virtual Int_t GetLen() const
Return the number of effective elements of this leaf, for the current entry.
Definition: TLeaf.cxx:311
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:78
TBranch * GetBranch() const
Definition: TLeaf.h:75
virtual Int_t GetLenStatic() const
Return the fixed length of this leaf.
Definition: TLeaf.h:86
virtual Bool_t IsUnsigned() const
Definition: TLeaf.h:104
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:467
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:589
Int_t GetEntriesFast() const
Definition: TObjArray.h:64
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
Definition: TObjArray.cxx:234
TObject * Last() const
Return the object in the last filled slot. Returns 0 if no entries.
Definition: TObjArray.cxx:505
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:522
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:89
virtual void Delete(Option_t *option="")
Remove all objects from the array AND delete all heap based objects.
Definition: TObjArray.cxx:355
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Definition: TObjArray.cxx:414
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:561
virtual void AddAt(TObject *obj, Int_t idx)
Add object at position ids.
Definition: TObjArray.cxx:253
TObject * At(Int_t idx) const
Definition: TObjArray.h:165
Mother of all ROOT objects.
Definition: TObject.h:37
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
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:880
void ResetBit(UInt_t f)
Definition: TObject.h:171
virtual Double_t Rndm()
Machine independent random number generator.
Definition: TRandom.cxx:533
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:43
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:487
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 datamember.
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 fLeaces 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 object has a header with a name and a title.
Definition: TTree.h:71
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:4631
virtual TObjArray * GetListOfLeaves()
Definition: TTree.h:428
virtual TVirtualIndex * GetTreeIndex() const
Definition: TTree.h:457
virtual Long64_t GetEntries() const
Definition: TTree.h:402
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:5843
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:5949
virtual Long64_t GetReadEntry() const
Definition: TTree.h:448
virtual TObjArray * GetListOfBranches()
Definition: TTree.h:427
virtual TTree * GetTree() const
Definition: TTree.h:456
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition: TTree.cxx:6226
virtual const char * GetAlias(const char *aliasName) const
Returns the expanded value of the alias. Search in the friends if any.
Definition: TTree.cxx:5010
virtual Int_t GetTreeNumber() const
Definition: TTree.h:458
virtual TLeaf * FindLeaf(const char *name)
Find leaf..
Definition: TTree.cxx:4703
virtual const char * GetFriendAlias(TTree *) const
If the 'tree' is a friend, this method returns its alias name.
Definition: TTree.cxx:5793
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
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
TClass * GetClass(T *)
Definition: TClass.h:582
static constexpr double second
Double_t CosH(Double_t)
Definition: TMath.h:641
Double_t ACos(Double_t)
Definition: TMath.h:656
Double_t ASin(Double_t)
Definition: TMath.h:649
Double_t Exp(Double_t x)
Definition: TMath.h:715
Double_t ATan(Double_t)
Definition: TMath.h:663
Double_t ASinH(Double_t)
Definition: TMath.cxx:64
Double_t TanH(Double_t)
Definition: TMath.h:645
Double_t ACosH(Double_t)
Definition: TMath.cxx:77
Double_t ATan2(Double_t, Double_t)
Definition: TMath.h:667
Double_t Log(Double_t x)
Definition: TMath.h:748
Double_t Sqrt(Double_t x)
Definition: TMath.h:679
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Definition: TMath.h:723
Double_t Cos(Double_t)
Definition: TMath.h:629
Double_t Sin(Double_t)
Definition: TMath.h:625
Double_t Tan(Double_t)
Definition: TMath.h:633
Double_t ATanH(Double_t)
Definition: TMath.cxx:90
Double_t Log10(Double_t x)
Definition: TMath.h:752
Short_t Abs(Short_t d)
Definition: TMathBase.h:120
Double_t SinH(Double_t)
Definition: TMath.h:637
Definition: first.py:1
Definition: tree.py:1
auto * m
Definition: textangle.C:8
auto * l
Definition: textangle.C:4
static long int sum(long int i)
Definition: Factory.cxx:2258
const UChar_t kTFOperShift
Definition: TFormula.h:33
const Int_t kTFOperMask
Definition: TFormula.h:32
const Int_t kMAXFOUND
Definition: TFormula.h:31