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