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