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