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