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