Logo ROOT   6.14/05
Reference Guide
TTreeFormula.cxx
Go to the documentation of this file.
1 // @(#)root/treeplayer:$Id$
2 // Author: Rene Brun 19/01/96
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TROOT.h"
13 #include "TTreeFormula.h"
14 #include "TTree.h"
15 #include "TBranch.h"
16 #include "TBranchObject.h"
17 #include "TFunction.h"
18 #include "TClonesArray.h"
19 #include "TLeafB.h"
20 #include "TLeafC.h"
21 #include "TLeafObject.h"
22 #include "TDataMember.h"
23 #include "TMethodCall.h"
24 #include "TCutG.h"
25 #include "TRandom.h"
26 #include "TInterpreter.h"
27 #include "TDataType.h"
28 #include "TStreamerInfo.h"
29 #include "TStreamerElement.h"
30 #include "TBranchElement.h"
31 #include "TLeafElement.h"
32 #include "TArrayI.h"
33 #include "TAxis.h"
34 #include "TError.h"
36 #include "TString.h"
37 #include "TTimeStamp.h"
38 #include "TMath.h"
39 
40 #include "TVirtualRefProxy.h"
41 #include "TTreeFormulaManager.h"
42 #include "TFormLeafInfo.h"
43 #include "TMethod.h"
44 #include "TBaseClass.h"
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 Helper using the leaf in TTreeFormula::fOper
116  Int_t fSize;
117  TFormLeafInfoMultiVarDim* fMultiDim;
118  TDimensionInfo(Int_t code, Int_t oper, Int_t size, TFormLeafInfoMultiVarDim* multiDim)
119  : fCode(code), fOper(oper), fSize(size), fMultiDim(multiDim) {};
120  ~TDimensionInfo() {};
121 };
122 
123 ////////////////////////////////////////////////////////////////////////////////
124 
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)
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)
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("DefinedVariable",
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("DefinedVariable","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  leafinfo = new TFormLeafInfoMethod(cl,method);
1415  cl = TFormLeafInfoMethod::ReturnTClass(method);
1416  }
1417  break;
1418  default:
1419  Error("DefineVariable","Method %s from %s has an impossible return type %d",
1420  work,cl->GetName(), (Int_t)method->ReturnType());
1421  return -2;
1422  }
1423  }
1424  if (maininfo==0) {
1425  maininfo = leafinfo;
1426  }
1427  if (previnfo==0) {
1428  previnfo = leafinfo;
1429  } else {
1430  previnfo->fNext = leafinfo;
1431  previnfo = leafinfo;
1432  }
1433  leafinfo = 0;
1434  current = &(work[0]);
1435  *current = 0;
1436  prevUseCollectionObject = kFALSE;
1437  prevUseReferenceObject = kFALSE;
1438  useCollectionObject = kFALSE;
1439 
1440  if (cl && cl->GetCollectionProxy()) {
1441  if (numberOfVarDim>1) {
1442  Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1443  cl->GetName());
1444  leafinfo = new TFormLeafInfo(cl,0,0);
1445  useCollectionObject = kTRUE;
1446  } else if (numberOfVarDim==0) {
1447  R__ASSERT(maininfo);
1448  leafinfo = new TFormLeafInfoCollection(cl,0,cl);
1449  numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1450  } else if (numberOfVarDim==1) {
1451  R__ASSERT(maininfo);
1452  leafinfo =
1454  (TStreamerElement*)0,maininfo);
1455  previnfo->fNext = leafinfo;
1456  previnfo = leafinfo;
1457  leafinfo = new TFormLeafInfoCollection(cl,0,cl);
1458 
1459  fHasMultipleVarDim[code] = kTRUE;
1460  numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1461  }
1462  previnfo->fNext = leafinfo;
1463  previnfo = leafinfo;
1464  leafinfo = 0;
1465  }
1466  continue;
1467  } else if (right[i] == ')') {
1468  // We should have the end of a cast operator. Let's introduce a TFormLeafCast
1469  // in the chain.
1470  TClass * casted = (TClass*) ((int(--paran_level)>=0) ? castqueue.At(paran_level) : 0);
1471  if (casted) {
1472  leafinfo = new TFormLeafInfoCast(cl,casted);
1473  fHasCast = kTRUE;
1474 
1475  if (maininfo==0) {
1476  maininfo = leafinfo;
1477  }
1478  if (previnfo==0) {
1479  previnfo = leafinfo;
1480  } else {
1481  previnfo->fNext = leafinfo;
1482  previnfo = leafinfo;
1483  }
1484  leafinfo = 0;
1485  current = &(work[0]);
1486  *current = 0;
1487 
1488  cl = casted;
1489  continue;
1490 
1491  }
1492  } else if (i > 0 && (right[i] == '.' || right[i] == '[' || right[i] == '\0') ) {
1493  // A delimiter happened let's see if what we have seen
1494  // so far does point to a data member.
1495  Bool_t needClass = kTRUE;
1496  *current = '\0';
1497 
1498  // skip it all if there is nothing to look at
1499  if (strlen(work)==0) continue;
1500 
1501  prevUseCollectionObject = useCollectionObject;
1502  prevUseReferenceObject = useReferenceObject;
1503  if (work[0]=='@') {
1504  useReferenceObject = kTRUE;
1505  useCollectionObject = kTRUE;
1506  Int_t l = 0;
1507  for(l=0;work[l+1]!=0;++l) work[l] = work[l+1];
1508  work[l] = '\0';
1509  } else if (work[strlen(work)-1]=='@') {
1510  useReferenceObject = kTRUE;
1511  useCollectionObject = kTRUE;
1512  work[strlen(work)-1] = '\0';
1513  } else {
1514  useReferenceObject = kFALSE;
1515  useCollectionObject = kFALSE;
1516  }
1517 
1518  Bool_t mustderef = kFALSE;
1519  if ( !prevUseReferenceObject && cl && cl->GetReferenceProxy() ) {
1520  R__LoadBranch(leaf->GetBranch(), readentry, fQuickLoad);
1521  if ( !maininfo ) {
1522  maininfo = previnfo = new TFormLeafInfoReference(cl, element, offset);
1523  if ( cl->GetReferenceProxy()->HasCounter() ) {
1524  numberOfVarDim += RegisterDimensions(code,-1);
1525  }
1526  prevUseReferenceObject = kFALSE;
1527  } else {
1528  previnfo->fNext = new TFormLeafInfoReference(cl, element, offset);
1529  previnfo = previnfo->fNext;
1530  }
1531  TVirtualRefProxy *refproxy = cl->GetReferenceProxy();
1532  cl = 0;
1533  for(Long64_t entry=0; entry<leaf->GetBranch()->GetEntries()-readentry; ++entry) {
1534  R__LoadBranch(leaf->GetBranch(), readentry+i, fQuickLoad);
1535  void *refobj = maininfo->GetValuePointer(leaf,0);
1536  if (refobj) {
1537  cl = refproxy->GetValueClass(refobj);
1538  }
1539  if ( cl ) break;
1540  }
1541  needClass = kFALSE;
1542  mustderef = kTRUE;
1543  }
1544  else if (!prevUseCollectionObject && cl == TClonesArray::Class()) {
1545  // We are not interested in the ClonesArray object but only
1546  // in its contents.
1547  // We need to retrieve the class of its content.
1548 
1549  TBranch *clbranch = leaf->GetBranch();
1550  R__LoadBranch(clbranch,readentry,fQuickLoad);
1551  TClonesArray * clones;
1552  if (maininfo) {
1553  clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
1554  } else {
1555  // we have a unsplit TClonesArray leaves
1556  // or we did not yet match any of the sub-branches!
1557 
1558  TClass *mother_cl;
1559  if (leaf->IsA()==TLeafObject::Class()) {
1560  // in this case mother_cl is not really used
1561  mother_cl = cl;
1562  } else {
1563  mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1564  }
1565 
1566  TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0);
1567  // The dimension needs to be handled!
1568  numberOfVarDim += RegisterDimensions(code,clonesinfo,maininfo,kFALSE);
1569 
1570  mustderef = kTRUE;
1571  previnfo = clonesinfo;
1572  maininfo = clonesinfo;
1573 
1574  if (clbranch->GetListOfBranches()->GetLast()>=0) {
1575  if (clbranch->IsA() != TBranchElement::Class()) {
1576  Error("DefinedVariable","Unimplemented usage of ClonesArray");
1577  return -2;
1578  }
1579  //clbranch = ((TBranchElement*)clbranch)->GetMother();
1580  clones = (TClonesArray*)((TBranchElement*)clbranch)->GetObject();
1581  } else
1582  clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1583  }
1584  // NOTE clones can be zero!
1585  if (clones==0) {
1586  Warning("DefinedVariable",
1587  "TClonesArray object was not retrievable for %s!",
1588  name.Data());
1589  return -1;
1590  }
1591  TClass * inside_cl = clones->GetClass();
1592 #if 1
1593  cl = inside_cl;
1594 #else
1595 /* Maybe we should make those test lead to warning messages */
1596  if (1 || inside_cl) cl = inside_cl;
1597  // if inside_cl is nul ... we have a problem of inconsistency :(
1598  if (0 && strlen(work)==0) {
1599  // However in this case we have NO content :(
1600  // so let get the number of objects
1601  //strcpy(work,"fLast");
1602  }
1603 #endif
1604  } else if (!prevUseCollectionObject && cl && cl->GetCollectionProxy() ) {
1605 
1606  // We are NEVER interested in the Collection object but only
1607  // in its contents.
1608  // We need to retrieve the class of its content.
1609 
1610  TBranch *clbranch = leaf->GetBranch();
1611  R__LoadBranch(clbranch,readentry,fQuickLoad);
1612 
1613  if (maininfo==0) {
1614 
1615  // we have a unsplit Collection leaf
1616  // or we did not yet match any of the sub-branches!
1617 
1618  TClass *mother_cl;
1619  if (leaf->IsA()==TLeafObject::Class()) {
1620  // in this case mother_cl is not really used
1621  mother_cl = cl;
1622  } else {
1623  mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1624  }
1625 
1626  TFormLeafInfo* collectioninfo =
1627  new TFormLeafInfoCollection(mother_cl, 0, cl);
1628  // The dimension needs to be handled!
1629  numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
1630 
1631  mustderef = kTRUE;
1632  previnfo = collectioninfo;
1633  maininfo = collectioninfo;
1634 
1635  } //else if (clbranch->GetStreamerType()==0) {
1636 
1637  //}
1638 
1639  TClass * inside_cl = cl->GetCollectionProxy()->GetValueClass();
1640 
1641  if (!inside_cl) {
1642  Error("DefinedVariable","Could you not find the inner class for %s with coll type = %d",
1643  cl->GetName(),cl->GetCollectionProxy()->GetType());
1644  }
1645  if (!inside_cl && cl->GetCollectionProxy()->GetType() > 0) {
1646  Warning("DefinedVariable","No data member in content of %s in %s\n",
1647  cl->GetName(),name.Data());
1648  }
1649  cl = inside_cl;
1650  // if inside_cl is nul ... we have a problem of inconsistency.
1651  }
1652 
1653  if (!cl) {
1654  if (leaf) leaf->GetBranch()->Print();
1655  Warning("DefinedVariable","Missing class for %s!",name.Data());
1656  } else {
1657  element = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1658  }
1659 
1660  if (!element && !prevUseCollectionObject) {
1661  // We allow for looking for a data member inside a class inside
1662  // a TClonesArray without mentioning the TClonesArrays variable name
1663  TIter next( cl->GetStreamerInfo()->GetElements() );
1664  TStreamerElement * curelem;
1665  while ((curelem = (TStreamerElement*)next())) {
1666  if (curelem->GetClassPointer() == TClonesArray::Class()) {
1667  Int_t clones_offset = 0;
1668  ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),clones_offset);
1669  TFormLeafInfo* clonesinfo =
1670  new TFormLeafInfo(cl, clones_offset, curelem);
1671  TClonesArray * clones;
1672  R__LoadBranch(leaf->GetBranch(),readentry,fQuickLoad);
1673 
1674  if (previnfo) {
1675  previnfo->fNext = clonesinfo;
1676  clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
1677  previnfo->fNext = 0;
1678  } else {
1679  clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1680  }
1681 
1682  TClass *sub_cl = clones->GetClass();
1683  if (sub_cl) element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1684  delete clonesinfo;
1685 
1686  if (element) {
1687  leafinfo = new TFormLeafInfoClones(cl,clones_offset,curelem);
1688  numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1689  if (maininfo==0) maininfo = leafinfo;
1690  if (previnfo==0) previnfo = leafinfo;
1691  else {
1692  previnfo->fNext = leafinfo;
1693  previnfo = leafinfo;
1694  }
1695  leafinfo = 0;
1696  cl = sub_cl;
1697  break;
1698  }
1699  } else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {
1700 
1701  Int_t coll_offset = 0;
1702  ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),coll_offset);
1703 
1704  TClass *sub_cl =
1705  curelem->GetClassPointer()->GetCollectionProxy()->GetValueClass();
1706  if (sub_cl) {
1707  element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1708  }
1709  if (element) {
1710  if (numberOfVarDim>1) {
1711  Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1712  curelem->GetName());
1713  leafinfo = new TFormLeafInfo(cl,coll_offset,curelem);
1714  useCollectionObject = kTRUE;
1715  } else if (numberOfVarDim==1) {
1716  R__ASSERT(maininfo);
1717  leafinfo =
1718  new TFormLeafInfoMultiVarDimCollection(cl,coll_offset,
1719  curelem,maininfo);
1720  fHasMultipleVarDim[code] = kTRUE;
1721  leafinfo->fNext = new TFormLeafInfoCollection(cl,coll_offset,curelem);
1722  numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1723  } else {
1724  leafinfo = new TFormLeafInfoCollection(cl,coll_offset,curelem);
1725  numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1726  }
1727  if (maininfo==0) maininfo = leafinfo;
1728  if (previnfo==0) previnfo = leafinfo;
1729  else {
1730  previnfo->fNext = leafinfo;
1731  previnfo = leafinfo;
1732  }
1733  if (leafinfo->fNext) {
1734  previnfo = leafinfo->fNext;
1735  }
1736  leafinfo = 0;
1737  cl = sub_cl;
1738  break;
1739  }
1740  }
1741  }
1742 
1743  }
1744 
1745  if (element) {
1746  Int_t type = element->GetNewType();
1747  if (type<60 && type!=0) {
1748  // This is a basic type ...
1749  if (numberOfVarDim>=1 && type>40) {
1750  // We have a variable array within a variable array!
1751  leafinfo = new TFormLeafInfoMultiVarDim(cl,offset,element,maininfo);
1752  fHasMultipleVarDim[code] = kTRUE;
1753  } else {
1754  if (leafinfo && type<=40 ) {
1755  leafinfo->AddOffset(offset,element);
1756  } else {
1757  leafinfo = new TFormLeafInfo(cl,offset,element);
1758  }
1759  }
1760  } else {
1761  Bool_t object = kFALSE;
1762  Bool_t pointer = kFALSE;
1763  Bool_t objarr = kFALSE;
1764  switch(type) {
1767  case TStreamerInfo::kSTLp:
1768  case TStreamerInfo::kAnyp:
1769  case TStreamerInfo::kAnyP:
1775  pointer = kTRUE;
1776  break;
1777  case TStreamerInfo::kBase:
1778  case TStreamerInfo::kAny :
1779  case TStreamerInfo::kSTL:
1784  object = kTRUE;
1785  break;
1789  objarr = kTRUE;
1790  break;
1793  // Unsupported case.
1794  Error("DefinedVariable",
1795  "%s is a datamember of %s BUT is not yet of a supported type (%d)",
1796  right,cl ? cl->GetName() : "unknown class",type);
1797  return -2;
1798  default:
1799  // Unknown and Unsupported case.
1800  Error("DefinedVariable",
1801  "%s is a datamember of %s BUT is not of a unknown type (%d)",
1802  right,cl ? cl->GetName() : "unknown class",type);
1803  return -2;
1804  }
1805 
1806  if (object && !useCollectionObject &&
1807  ( element->GetClassPointer() == TClonesArray::Class()
1808  || element->GetClassPointer()->GetCollectionProxy() ) )
1809  {
1810  object = kFALSE;
1811  }
1812  if (object && leafinfo) {
1813  leafinfo->AddOffset(offset,element);
1814  } else if (objarr) {
1815  // This is an embedded array of objects. We can not increase the offset.
1816  leafinfo = new TFormLeafInfo(cl,offset,element);
1817  mustderef = kTRUE;
1818  } else {
1819 
1820  if (!useCollectionObject && element->GetClassPointer() == TClonesArray::Class()) {
1821 
1822  leafinfo = new TFormLeafInfoClones(cl,offset,element);
1823  mustderef = kTRUE;
1824 
1825  } else if (!useCollectionObject && element->GetClassPointer()
1826  && element->GetClassPointer()->GetCollectionProxy()) {
1827 
1828  mustderef = kTRUE;
1829  if (numberOfVarDim>1) {
1830  Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1831  element->GetName());
1832  leafinfo = new TFormLeafInfo(cl,offset,element);
1833  useCollectionObject = kTRUE;
1834  } else if (numberOfVarDim==1) {
1835  R__ASSERT(maininfo);
1836  leafinfo =
1837  new TFormLeafInfoMultiVarDimCollection(cl,offset,element,maininfo);
1838 
1839  fHasMultipleVarDim[code] = kTRUE;
1840  //numberOfVarDim += RegisterDimensions(code,leafinfo);
1841  //cl = cl->GetCollectionProxy()->GetValueClass();
1842 
1843  //if (maininfo==0) maininfo = leafinfo;
1844  //if (previnfo==0) previnfo = leafinfo;
1845  //else {
1846  // previnfo->fNext = leafinfo;
1847  // previnfo = leafinfo;
1848  //}
1849  leafinfo->fNext = new TFormLeafInfoCollection(cl, offset, element);
1850  if (element->GetClassPointer()->GetCollectionProxy()->GetValueClass()==0) {
1852  element->GetClassPointer()->GetCollectionProxy());
1853  if (leafinfo->fNext) leafinfo->fNext->fNext = info;
1854  else leafinfo->fNext = info;
1855  }
1856  } else {
1857  leafinfo = new TFormLeafInfoCollection(cl, offset, element);
1858 
1859  TClass *elemCl = element->GetClassPointer();
1860  TClass *valueCl = elemCl->GetCollectionProxy()->GetValueClass();
1861  if (!maininfo) maininfo = leafinfo;
1862 
1863  if (valueCl!=0 && valueCl->GetCollectionProxy()!=0) {
1864 
1865  numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
1866  if (previnfo==0) previnfo = leafinfo;
1867  else {
1868  previnfo->fNext = leafinfo;
1869  previnfo = leafinfo;
1870  }
1871  leafinfo = new TFormLeafInfoMultiVarDimCollection(elemCl,0,
1872  elemCl->GetCollectionProxy()->GetValueClass(),maininfo);
1873  //numberOfVarDim += RegisterDimensions(code,previnfo->fNext);
1874  fHasMultipleVarDim[code] = kTRUE;
1875  //previnfo = previnfo->fNext;
1876  leafinfo->fNext = new TFormLeafInfoCollection(elemCl,0,
1877  valueCl);
1878  elemCl = valueCl;
1879  }
1880  if (elemCl->GetCollectionProxy() &&
1881  elemCl->GetCollectionProxy()->GetValueClass()==0) {
1883  if (leafinfo->fNext) leafinfo->fNext->fNext = info;
1884  else leafinfo->fNext = info;
1885  }
1886  }
1887  } else if ( (object || pointer) && !useReferenceObject && element->GetClassPointer()->GetReferenceProxy() ) {
1888  TClass* c = element->GetClassPointer();
1889  R__LoadBranch(leaf->GetBranch(),readentry,fQuickLoad);
1890  if ( object ) {
1891  leafinfo = new TFormLeafInfoReference(c, element, offset);
1892  }
1893  else {
1894  leafinfo = new TFormLeafInfoPointer(cl,offset,element);
1895  leafinfo->fNext = new TFormLeafInfoReference(c, element, 0);
1896  }
1897  //if ( c->GetReferenceProxy()->HasCounter() ) {
1898  // numberOfVarDim += RegisterDimensions(code,-1);
1899  //}
1900  prevUseReferenceObject = kFALSE;
1901  needClass = kFALSE;
1902  mustderef = kTRUE;
1903  } else if (pointer) {
1904  // this is a pointer to be followed.
1905  leafinfo = new TFormLeafInfoPointer(cl,offset,element);
1906  mustderef = kTRUE;
1907  } else {
1908  // this is an embedded object.
1909  R__ASSERT(object);
1910  leafinfo = new TFormLeafInfo(cl,offset,element);
1911  }
1912  }
1913  }
1914  } else {
1915  if (cl) Error("DefinedVariable","%s is not a datamember of %s",work,cl->GetName());
1916  // no else, we warned earlier that the class was missing.
1917  return -1;
1918  }
1919 
1920  numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,useCollectionObject); // Note or useCollectionObject||prevUseColectionObject
1921  if (maininfo==0) {
1922  maininfo = leafinfo;
1923  }
1924  if (previnfo==0) {
1925  previnfo = leafinfo;
1926  } else if (previnfo!=leafinfo) {
1927  previnfo->fNext = leafinfo;
1928  previnfo = leafinfo;
1929  }
1930  while (previnfo->fNext) previnfo = previnfo->fNext;
1931 
1932  if ( right[i] != '\0' ) {
1933  if ( !needClass && mustderef ) {
1934  maininfo->SetBranch(leaf->GetBranch());
1935  char *ptr = (char*)maininfo->GetValuePointer(leaf,0);
1936  TFormLeafInfoReference* refInfo = 0;
1937  if ( !maininfo->IsReference() ) {
1938  for( TFormLeafInfo* inf = maininfo->fNext; inf; inf = inf->fNext ) {
1939  if ( inf->IsReference() ) {
1940  refInfo = (TFormLeafInfoReference*)inf;
1941  }
1942  }
1943  }
1944  else {
1945  refInfo = (TFormLeafInfoReference*)maininfo;
1946  }
1947  if ( refInfo ) {
1948  cl = refInfo->GetValueClass(ptr);
1949  if ( !cl ) {
1950  Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1951  return -1;
1952  }
1953  element = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1954  }
1955  else {
1956  Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1957  return -1;
1958  }
1959  }
1960  else if ( needClass ) {
1961  cl = element->GetClassPointer();
1962  }
1963  }
1964  if (mustderef) leafinfo = 0;
1965  current = &(work[0]);
1966  *current = 0;
1967  R__ASSERT(right[i] != '['); // We are supposed to have removed all dimensions already!
1968 
1969  if (cl == TString::Class() && strcmp(right+i+1,"fData") == 0) {
1970  // For backward compatibility replace TString::fData which no longer exist
1971  // by a call to TString::Data()
1972  right = ".Data()";
1973  i = 0;
1974  nchname = strlen(right);
1975  }
1976 
1977  } else
1978  *current++ = right[i];
1979  }
1980  if (maininfo) {
1981  fDataMembers.AddAtAndExpand(maininfo,code);
1982  if (leaf) fLookupType[code] = kDataMember;
1983  else fLookupType[code] = kTreeMember;
1984  }
1985  }
1986 
1987  if (strlen(work)!=0) {
1988  // We have something left to analyze. Let's make this an error case!
1989  return -1;
1990  }
1991 
1992  TClass *objClass = EvalClass(code);
1993  if (objClass && !useLeafCollectionObject && objClass->GetCollectionProxy() && objClass->GetCollectionProxy()->GetValueClass()) {
1994  TFormLeafInfo *last = 0;
1995  if ( SwitchToFormLeafInfo(code) ) {
1996 
1997  last = (TFormLeafInfo*)fDataMembers.At(code);
1998 
1999  if (!last) return action;
2000  while (last->fNext) { last = last->fNext; }
2001 
2002  }
2003  if (last && last->GetClass() != objClass) {
2004  TClass *mother_cl;
2005  if (leaf->IsA()==TLeafObject::Class()) {
2006  // in this case mother_cl is not really used
2007  mother_cl = cl;
2008  } else {
2009  mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
2010  }
2011 
2012  TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(mother_cl, 0, objClass, kFALSE);
2013  // The dimension needs to be handled!
2014  numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
2015  last->fNext = collectioninfo;
2016  }
2017  numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0
2018  objClass = objClass->GetCollectionProxy()->GetValueClass();
2019  }
2020  if (IsLeafString(code) || objClass == TString::Class() || objClass == stdStringClass) {
2021 
2022  TFormLeafInfo *last = 0;
2023  if ( SwitchToFormLeafInfo(code) ) {
2024 
2025  last = (TFormLeafInfo*)fDataMembers.At(code);
2026 
2027  if (!last) return action;
2028  while (last->fNext) { last = last->fNext; }
2029 
2030  }
2031  const char *funcname = 0;
2032  if (objClass == TString::Class()) {
2033  funcname = "Data";
2034  //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2035  } else if (objClass == stdStringClass) {
2036  funcname = "c_str";
2037  //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2038  }
2039  if (funcname) {
2040  TMethodCall *method = new TMethodCall(objClass, funcname, "");
2041  if (last) {
2042  last->fNext = new TFormLeafInfoMethod(objClass,method);
2043  } else {
2044  fDataMembers.AddAtAndExpand(new TFormLeafInfoMethod(objClass,method),code);
2045  if (leaf) fLookupType[code] = kDataMember;
2046  else fLookupType[code] = kTreeMember;
2047  }
2048  }
2049  return kDefinedString;
2050  }
2051 
2052  if (objClass) {
2053  TMethodCall *method = new TMethodCall(objClass, "AsDouble", "");
2054  if (method->IsValid()
2055  && (method->ReturnType() == TMethodCall::kLong || method->ReturnType() == TMethodCall::kDouble)) {
2056 
2057  TFormLeafInfo *last = 0;
2058  if (SwitchToFormLeafInfo(code)) {
2059  last = (TFormLeafInfo*)fDataMembers.At(code);
2060  // Improbable case
2061  if (!last) {
2062  delete method;
2063  return action;
2064  }
2065  while (last->fNext) { last = last->fNext; }
2066  }
2067  if (last) {
2068  last->fNext = new TFormLeafInfoMethod(objClass,method);
2069  } else {
2070  fDataMembers.AddAtAndExpand(new TFormLeafInfoMethod(objClass,method),code);
2071  if (leaf) fLookupType[code] = kDataMember;
2072  else fLookupType[code] = kTreeMember;
2073  }
2074 
2075  return kDefinedVariable;
2076  }
2077  delete method;
2078  method = new TMethodCall(objClass, "AsString", "");
2079  if (method->IsValid()
2080  && method->ReturnType() == TMethodCall::kString) {
2081 
2082  TFormLeafInfo *last = 0;
2083  if (SwitchToFormLeafInfo(code)) {
2084  last = (TFormLeafInfo*)fDataMembers.At(code);
2085  // Improbable case
2086  if (!last) {
2087  delete method;
2088  return action;
2089  }
2090  while (last->fNext) { last = last->fNext; }
2091  }
2092  if (last) {
2093  last->fNext = new TFormLeafInfoMethod(objClass,method);
2094  } else {
2095  fDataMembers.AddAtAndExpand(new TFormLeafInfoMethod(objClass,method),code);
2096  if (leaf) fLookupType[code] = kDataMember;
2097  else fLookupType[code] = kTreeMember;
2098  }
2099 
2100  //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2101  return kDefinedString;
2102  }
2103  if (method->IsValid()
2104  && method->ReturnType() == TMethodCall::kOther) {
2105 
2107  if ((rcl == TString::Class() || rcl == stdStringClass) ) {
2108 
2109  TFormLeafInfo *last = 0;
2110  if (SwitchToFormLeafInfo(code)) {
2111  last = (TFormLeafInfo*)fDataMembers.At(code);
2112  // Improbable case
2113  if (!last) {
2114  delete method;
2115  return action;
2116  }
2117  while (last->fNext) { last = last->fNext; }
2118  }
2119  if (last) {
2120  last->fNext = new TFormLeafInfoMethod(objClass,method);
2121  last = last->fNext;
2122  } else {
2123  last = new TFormLeafInfoMethod(objClass,method);
2124  fDataMembers.AddAtAndExpand(last,code);
2125  if (leaf) fLookupType[code] = kDataMember;
2126  else fLookupType[code] = kTreeMember;
2127  }
2128 
2129  objClass = rcl;
2130 
2131  const char *funcname = 0;
2132  if (objClass == TString::Class()) {
2133  funcname = "Data";
2134  } else if (objClass == stdStringClass) {
2135  funcname = "c_str";
2136  }
2137  if (funcname) {
2138  method = new TMethodCall(objClass, funcname, "");
2139  last->fNext = new TFormLeafInfoMethod(objClass,method);
2140  }
2141  return kDefinedString;
2142  }
2143  }
2144  delete method;
2145  }
2146 
2147  return action;
2148 }
2149 
2150 ////////////////////////////////////////////////////////////////////////////////
2151 /// Look for the leaf corresponding to the start of expression.
2152 /// It returns the corresponding leaf if any.
2153 /// It also modify the following arguments:
2154 ///
2155 /// - leftover: contain from expression that was not used to determine the leaf
2156 /// - final:
2157 /// * paran_level: number of un-matched open parenthesis
2158 /// * cast_queue: list of cast to be done
2159 /// * aliases: list of aliases used
2160 /// - Return <0 in case of failure
2161 ///
2162 /// - Return 0 if a leaf has been found
2163 /// - Return 2 if info about the TTree itself has been requested.
2164 
2165 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)
2166 {
2167  // Later on we will need to read one entry, let's make sure
2168  // it is a real entry.
2169  if (fTree->GetTree()==0) {
2170  fTree->LoadTree(0);
2171  if (fTree->GetTree()==0) return -1;
2172  }
2173  Long64_t readentry = fTree->GetTree()->GetReadEntry();
2174  if (readentry < 0) readentry=0;
2175  const char *cname = expression;
2176  char first[kMaxLen]; first[0] = '\0';
2177  char second[kMaxLen]; second[0] = '\0';
2178  char right[kMaxLen]; right[0] = '\0';
2179  char work[kMaxLen]; work[0] = '\0';
2180  char left[kMaxLen]; left[0] = '\0';
2181  char scratch[kMaxLen];
2182  char scratch2[kMaxLen];
2183  std::string currentname;
2184  Int_t previousdot = 0;
2185  char *current;
2186  TLeaf *tmp_leaf=0;
2187  TBranch *branch=0, *tmp_branch=0;
2188  Int_t nchname = strlen(cname);
2189  Int_t i;
2190  Bool_t foundAtSign = kFALSE;
2191  Bool_t startWithParan = kFALSE;
2192 
2193  for (i=0, current = &(work[0]); i<=nchname && !final;i++ ) {
2194  // We will treated the terminator as a token.
2195  *current++ = cname[i];
2196 
2197  if (cname[i] == '(') {
2198  ++paran_level;
2199 
2200  if (current==work+1) {
2201  // If the expression starts with a paranthesis, we are likely
2202  // to have a cast operator inside.
2203  startWithParan = kTRUE;
2204  current--;
2205  }
2206  continue;
2207  //i++;
2208  //while( cname[i]!=')' && cname[i] ) {
2209  // *current++ = cname[i++];
2210  //}
2211  //*current++ = cname[i];
2212  ////*current = 0;
2213  //continue;
2214  }
2215  if (cname[i] == ')') {
2216  if (paran_level==0) {
2217  Error("DefinedVariable","Unmatched paranthesis in %s",fullExpression);
2218  return -1;
2219  }
2220  paran_level--;
2221 
2222  if (startWithParan) {
2223  startWithParan = kFALSE; // the next match wont be against the starting paranthesis.
2224 
2225  // Let's see if work is a classname and thus we have a cast.
2226  *(--current) = 0;
2227  TString cast_name = gInterpreter->TypeName(work);
2228  TClass *cast_cl = TClass::GetClass(cast_name);
2229  if (cast_cl) {
2230  // We must have a cast
2231  castqueue.AddAtAndExpand(cast_cl,paran_level);
2232  current = &(work[0]);
2233  *current = 0;
2234  // Warning("DefinedVariable","Found cast to %s",cast_fullExpression);
2235  continue;
2236  } else if (gROOT->GetType(cast_name)) {
2237  // We reset work
2238  current = &(work[0]);
2239  *current = 0;
2240  Warning("DefinedVariable",
2241  "Casting to primary types like \"%s\" is not supported yet",cast_name.Data());
2242  continue;
2243  }
2244  *(current++)=')';
2245  }
2246 
2247  *current='\0';
2248  char *params = strchr(work,'(');
2249  if (params) {
2250  *params = 0; params++;
2251 
2252  if (branch && !leaf) {
2253  // We have a branch but not a leaf. We are likely to have found
2254  // the top of split branch.
2255  if (BranchHasMethod(0, branch, work, params, readentry)) {
2256  //fprintf(stderr, "Does have a method %s for %s.\n", work, branch->GetName());
2257  }
2258  }
2259 
2260  // What we have so far might be a member function of one of the
2261  // leaves that are not split (for example "GetNtrack" for the Event class).
2263  TLeaf* leafcur = 0;
2264  while (!leaf && (leafcur = (TLeaf*) next())) {
2265  TBranch* br = leafcur->GetBranch();
2266  Bool_t yes = BranchHasMethod(leafcur, br, work, params, readentry);
2267  if (yes) {
2268  leaf = leafcur;
2269  //fprintf(stderr, "Does have a method %s for %s found in leafcur %s.\n", work, leafcur->GetBranch()->GetName(), leafcur->GetName());
2270  }
2271  }
2272  if (!leaf) {
2273  // Check for an alias.
2274  if (strlen(left) && left[strlen(left)-1]=='.') left[strlen(left)-1]=0;
2275  const char *aliasValue = fTree->GetAlias(left);
2276  if (aliasValue && strcspn(aliasValue,"+*/-%&!=<>|")==strlen(aliasValue)) {
2277  // First check whether we are using this alias recursively (this would
2278  // lead to an infinite recursion.
2279  if (find(aliasUsed.begin(),
2280  aliasUsed.end(),
2281  left) != aliasUsed.end()) {
2282  Error("DefinedVariable",
2283  "The substitution of the branch alias \"%s\" by \"%s\" in \"%s\" failed\n"\
2284  "\tbecause \"%s\" is used [recursively] in its own definition!",
2285  left,aliasValue,fullExpression,left);
2286  return -3;
2287  }
2288  aliasUsed.push_back(left);
2289  TString newExpression = aliasValue;
2290  newExpression += (cname+strlen(left));
2291  Int_t res = FindLeafForExpression(newExpression, leaf, leftover, final, paran_level,
2292  castqueue, aliasUsed, useLeafCollectionObject, fullExpression);
2293  if (res<0) {
2294  Error("DefinedVariable",
2295  "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue);
2296  return -3;
2297  }
2298  return res;
2299  }
2300 
2301  // This is actually not really any error, we probably received something
2302  // like "abs(some_val)", let ROOT::v5::TFormula decompose it first.
2303  return -1;
2304  }
2305  // if (!leaf->InheritsFrom(TLeafObject::Class()) ) {
2306  // If the leaf that we found so far is not a TLeafObject then there is
2307  // nothing we would be able to do.
2308  // Error("DefinedVariable","Need a TLeafObject to call a function!");
2309  // return -1;
2310  //}
2311  // We need to recover the info not used.
2312  strlcpy(right,work,kMaxLen);
2313  strncat(right,"(",kMaxLen-1-strlen(right));
2314  strncat(right,params,kMaxLen-1-strlen(right));
2315  final = kTRUE;
2316 
2317  // Record in 'i' what we consumed
2318  i += strlen(params);
2319 
2320  // we reset work
2321  current = &(work[0]);
2322  *current = 0;
2323  break;
2324  }
2325  }
2326  if (cname[i] == '.' || cname[i] == '\0' || cname[i] == ')') {
2327  // A delimiter happened let's see if what we have seen
2328  // so far does point to a leaf.
2329  *current = '\0';
2330 
2331  Int_t len = strlen(work);
2332  if (work[0]=='@') {
2333  foundAtSign = kTRUE;
2334  Int_t l = 0;
2335  for(l=0;work[l+1]!=0;++l) work[l] = work[l+1];
2336  work[l] = '\0';
2337  --current;
2338  } else if (len>=2 && work[len-2]=='@') {
2339  foundAtSign = kTRUE;
2340  work[len-2] = cname[i];
2341  work[len-1] = '\0';
2342  --current;
2343  } else {
2344  foundAtSign = kFALSE;
2345  }
2346 
2347  if (left[0]==0) strlcpy(left,work,kMaxLen);
2348  if (!leaf && !branch) {
2349  // So far, we have not found a matching leaf or branch.
2350  strlcpy(first,work,kMaxLen);
2351 
2352  std::string treename(first);
2353  if (treename.size() && treename[treename.size()-1]=='.') {
2354  treename.erase(treename.size()-1);
2355  }
2356  if (treename== "This" /* || treename == fTree->GetName() */ ) {
2357  // Request info about the TTree object itself,
2358  TNamed *named = new TNamed(fTree->GetName(),fTree->GetName());
2361  if (cname[i]) leftover = &(cname[i+1]);
2362  return 2;
2363  }
2364  // The following would allow to access the friend by name
2365  // however, it would also prevent the access of the leaves
2366  // within the friend. We could use the '@' notation here
2367  // however this would not be aesthetically pleasing :(
2368  // What we need to do, is add the ability to look ahead to
2369  // the next 'token' to decide whether we to access the tree
2370  // or its leaf.
2371  //} else {
2372  // TTree *tfriend = fTree->GetFriend(treename.c_str());
2373  // TTree *realtree = fTree->GetTree();
2374  // if (!tfriend && realtree != fTree){
2375  // // If it is a chain and we did not find a friend,
2376  // // let's try with the internal tree.
2377  // tfriend = realtree->GetFriend(treename.c_str());
2378  // }
2379  // if (tfriend) {
2380  // TNamed *named = new TNamed(treename.c_str(),tfriend->GetName());
2381  // fLeafNames.AddAtAndExpand(named,fNcodes);
2382  // fLeaves.AddAtAndExpand(tfriend,fNcodes);
2383  // if (cname[i]) leftover = &(cname[i+1]);
2384  // return 2;
2385  // }
2386  //}
2387 
2388  branch = fTree->FindBranch(first);
2389  leaf = fTree->FindLeaf(first);
2390 
2391  // Now look with the delimiter removed (we looked with it first
2392  // because a dot is allowed at the end of some branches).
2393  if (cname[i]) first[strlen(first)-1]='\0';
2394  if (!branch) branch = fTree->FindBranch(first);
2395  if (!leaf) leaf = fTree->FindLeaf(first);
2396  TClass* cl = 0;
2397  if ( branch && branch->InheritsFrom(TBranchElement::Class()) ) {
2398  int offset=0;
2399  TBranchElement* bElt = (TBranchElement*)branch;
2400  TStreamerInfo* info = bElt->GetInfo();
2401  TStreamerElement* element = info ? info->GetStreamerElement(first,offset) : 0;
2402  if (element) cl = element->GetClassPointer();
2403  if ( cl && !cl->GetReferenceProxy() ) cl = 0;
2404  }
2405  if ( cl ) { // We have a reference class here....
2406  final = kTRUE;
2407  useLeafCollectionObject = foundAtSign;
2408  // we reset work
2409  current = &(work[0]);
2410  *current = 0;
2411  }
2412  else if (branch && (foundAtSign || cname[i] != 0) ) {
2413  // Since we found a branch and there is more information in the name,
2414  // we do NOT look at the 'IsOnTerminalBranch' status of the leaf
2415  // we found ... yet!
2416 
2417  if (leaf==0) {
2418  // Note we do not know (yet?) what (if anything) to do
2419  // for a TBranchObject branch.
2420  if (branch->InheritsFrom(TBranchElement::Class()) ) {
2421  Int_t type = ((TBranchElement*)branch)->GetType();
2422  if ( type == 3 || type ==4) {
2423  // We have a Collection branch.
2424  leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
2425  if (foundAtSign) {
2426  useLeafCollectionObject = foundAtSign;
2427  foundAtSign = kFALSE;
2428  current = &(work[0]);
2429  *current = 0;
2430  ++i;
2431  break;
2432  }
2433  }
2434  }
2435  }
2436 
2437  // we reset work
2438  useLeafCollectionObject = foundAtSign;
2439  foundAtSign = kFALSE;
2440  current = &(work[0]);
2441  *current = 0;
2442  } else if (leaf || branch) {
2443  if (leaf && branch) {
2444  // We found both a leaf and branch matching the request name
2445  // let's see which one is the proper one to use! (On annoying case
2446  // is that where the same name is repeated ( varname.varname )
2447 
2448  // We always give priority to the branch
2449  // leaf = 0;
2450  }
2451  if (leaf && leaf->IsOnTerminalBranch()) {
2452  // This is a non-object leaf, it should NOT be specified more except for
2453  // dimensions.
2454  final = kTRUE;
2455  }
2456  // we reset work
2457  current = &(work[0]);
2458  *current = 0;
2459  } else {
2460  // What we have so far might be a data member of one of the
2461  // leaves that are not split (for example "fNtrack" for the Event class.
2462  TLeaf *leafcur = GetLeafWithDatamember(first,work,readentry);
2463  if (leafcur) {
2464  leaf = leafcur;
2465  branch = leaf->GetBranch();
2466  if (leaf->IsOnTerminalBranch()) {
2467  final = kTRUE;
2468  strlcpy(right,first,kMaxLen);
2469  //We need to put the delimiter back!
2470  if (foundAtSign) strncat(right,"@",kMaxLen-1-strlen(right));
2471  if (cname[i]=='.') strncat(right,".",kMaxLen-1-strlen(right));
2472 
2473  // We reset work
2474  current = &(work[0]);
2475  *current = 0;
2476  };
2477  } else if (cname[i] == '.') {
2478  // If we have a branch that match a name preceded by a dot
2479  // then we assume we are trying to drill down the branch
2480  // Let look if one of the top level branch has a branch with the name
2481  // we are looking for.
2482  TBranch *branchcur;
2483  TIter next( fTree->GetListOfBranches() );
2484  while(!branch && (branchcur=(TBranch*)next()) ) {
2485  branch = branchcur->FindBranch(first);
2486  }
2487  if (branch) {
2488  // We reset work
2489  current = &(work[0]);
2490  *current = 0;
2491  }
2492  }
2493  }
2494  } else { // correspond to if (leaf || branch)
2495  if (final) {
2496  Error("DefinedVariable", "Unexpected control flow!");
2497  return -1;
2498  }
2499 
2500  // No dot is allowed in subbranches and leaves, so
2501  // we always remove it in the present case.
2502  if (cname[i]) work[strlen(work)-1] = '\0';
2503  snprintf(scratch,sizeof(scratch),"%s.%s",first,work);
2504  snprintf(scratch2,sizeof(scratch2),"%s.%s.%s",first,second,work);
2505 
2506  if (previousdot) {
2507  currentname = &(work[previousdot+1]);
2508  }
2509 
2510  // First look for the current 'word' in the list of
2511  // leaf of the
2512  if (branch) {
2513  tmp_leaf = branch->FindLeaf(work);
2514  if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch);
2515  if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch2);
2516  if (!tmp_leaf) tmp_leaf = branch->FindLeaf(currentname.c_str());
2517  }
2518  if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
2519  // This is a non-object leaf, it should NOT be specified more except for
2520  // dimensions.
2521  final = kTRUE;
2522  }
2523 
2524  if (branch) {
2525  tmp_branch = branch->FindBranch(work);
2526  if (!tmp_branch) tmp_branch = branch->FindBranch(scratch);
2527  if (!tmp_branch) tmp_branch = branch->FindBranch(scratch2);
2528  if (!tmp_branch) tmp_branch = branch->FindBranch(currentname.c_str());
2529  }
2530  if (tmp_branch) {
2531  branch=tmp_branch;
2532 
2533  // NOTE: Should we look for a leaf within here?
2534  if (!final) {
2535  tmp_leaf = branch->FindLeaf(work);
2536  if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch);
2537  if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch2);
2538  if (!tmp_leaf) tmp_leaf = branch->FindLeaf(currentname.c_str());
2539  if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
2540  // This is a non-object leaf, it should NOT be specified
2541  // more except for dimensions.
2542  final = kTRUE;
2543  leaf = tmp_leaf;
2544  }
2545  }
2546  }
2547  if (tmp_leaf) {
2548  // Something was found.
2549  if (second[0]) strncat(second,".",kMaxLen-1-strlen(second));
2550  strncat(second,work,kMaxLen-1-strlen(second));
2551  leaf = tmp_leaf;
2552  useLeafCollectionObject = foundAtSign;
2553  foundAtSign = kFALSE;
2554 
2555  // we reset work
2556  current = &(work[0]);
2557  *current = 0;
2558  } else {
2559  //We need to put the delimiter back!
2560  if (strlen(work)) {
2561  if (foundAtSign) {
2562  Int_t where = strlen(work);
2563  work[where] = '@';
2564  work[where+1] = cname[i];
2565  ++current;
2566  previousdot = where+1;
2567  } else {
2568  previousdot = strlen(work);
2569  work[strlen(work)] = cname[i];
2570  }
2571  } else --current;
2572  }
2573  }
2574  }
2575  }
2576 
2577  // Copy the left over for later use.
2578  if (strlen(work)) {
2579  strncat(right,work,kMaxLen-1-strlen(right));
2580  }
2581 
2582  if (i<nchname) {
2583  if (strlen(right) && right[strlen(right)-1]!='.' && cname[i]!='.') {
2584  // In some cases we remove a little to fast the period, we add
2585  // it back if we need. It is assumed that 'right' and the rest of
2586  // the name was cut by a delimiter, so this should be safe.
2587  strncat(right,".",kMaxLen-1-strlen(right));
2588  }
2589  strncat(right,&cname[i],kMaxLen-1-strlen(right));
2590  }
2591 
2592  if (!final && branch) {
2593  if (!leaf) {
2594  leaf = (TLeaf*)branch->GetListOfLeaves()->UncheckedAt(0);
2595  if (!leaf) return -1;
2596  }
2597  final = leaf->IsOnTerminalBranch();
2598  }
2599 
2600  if (leaf && leaf->InheritsFrom(TLeafObject::Class()) ) {
2601  if (strlen(right)==0) strlcpy(right,work,kMaxLen);
2602  }
2603 
2604  if (leaf==0 && left[0]!=0) {
2605  if (left[strlen(left)-1]=='.') left[strlen(left)-1]=0;
2606 
2607  // Check for an alias.
2608  const char *aliasValue = fTree->GetAlias(left);
2609  if (aliasValue && strcspn(aliasValue,"[]+*/-%&!=<>|")==strlen(aliasValue)) {
2610  // First check whether we are using this alias recursively (this would
2611  // lead to an infinite recursion).
2612  if (find(aliasUsed.begin(),
2613  aliasUsed.end(),
2614  left) != aliasUsed.end()) {
2615  Error("DefinedVariable",
2616  "The substitution of the branch alias \"%s\" by \"%s\" in \"%s\" failed\n"\
2617  "\tbecause \"%s\" is used [recursively] in its own definition!",
2618  left,aliasValue,fullExpression,left);
2619  return -3;
2620  }
2621  aliasUsed.push_back(left);
2622  TString newExpression = aliasValue;
2623  newExpression += (cname+strlen(left));
2624  Int_t res = FindLeafForExpression(newExpression, leaf, leftover, final, paran_level,
2625  castqueue, aliasUsed, useLeafCollectionObject, fullExpression);
2626  if (res<0) {
2627  Error("DefinedVariable",
2628  "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue);
2629  return -3;
2630  }
2631  return res;
2632  }
2633  }
2634  leftover = right;
2635 
2636  return 0;
2637 }
2638 
2639 ////////////////////////////////////////////////////////////////////////////////
2640 /// Check if name is in the list of Tree/Branch leaves.
2641 ///
2642 /// This member function redefines the function in ROOT::v5::TFormula
2643 /// If a leaf has a name corresponding to the argument name, then
2644 /// returns a new code.
2645 ///
2646 /// A TTreeFormula may contain more than one variable.
2647 /// For each variable referenced, the pointers to the corresponding
2648 /// branch and leaf is stored in the object arrays fBranches and fLeaves.
2649 ///
2650 /// name can be :
2651 /// - Leaf_Name (simple variable or data member of a ClonesArray)
2652 /// - Branch_Name.Leaf_Name
2653 /// - Branch_Name.Method_Name
2654 /// - Leaf_Name[index]
2655 /// - Branch_Name.Leaf_Name[index]
2656 /// - Branch_Name.Leaf_Name[index1]
2657 /// - Branch_Name.Leaf_Name[][index2]
2658 /// - Branch_Name.Leaf_Name[index1][index2]
2659 ///
2660 /// New additions:
2661 /// - Branch_Name.Leaf_Name[OtherLeaf_Name]
2662 /// - Branch_Name.Datamember_Name
2663 /// - '.' can be replaced by '->'
2664 ///
2665 /// and
2666 /// - Branch_Name[index1].Leaf_Name[index2]
2667 /// - Leaf_name[index].Action().OtherAction(param)
2668 /// - Leaf_name[index].Action()[val].OtherAction(param)
2669 ///
2670 /// The expected returns values are
2671 /// - -2 : the name has been recognized but won't be usable
2672 /// - -1 : the name has not been recognized
2673 /// - >=0 : the name has been recognized, return the internal code for this name.
2674 
2676 {
2677 
2678  action = kDefinedVariable;
2679  if (!fTree) return -1;
2680 
2681  fNpar = 0;
2682  if (name.Length() > kMaxLen) return -1;
2683  Int_t i,k;
2684 
2685  if (name == "Entry$") {
2686  Int_t code = fNcodes++;
2687  fCodes[code] = 0;
2688  fLookupType[code] = kIndexOfEntry;
2689  return code;
2690  }
2691  if (name == "LocalEntry$") {
2692  Int_t code = fNcodes++;
2693  fCodes[code] = 0;
2695  return code;
2696  }
2697  if (name == "Entries$") {
2698  Int_t code = fNcodes++;
2699  fCodes[code] = 0;
2700  fLookupType[code] = kEntries;
2703  return code;
2704  }
2705  if (name == "LocalEntries$") {
2706  Int_t code = fNcodes++;
2707  fCodes[code] = 0;
2708  fLookupType[code] = kLocalEntries;
2709  SetBit(kNeedEntries); // FIXME: necessary?
2710  fManager->SetBit(kNeedEntries); // FIXME: necessary?
2711  return code;
2712  }
2713  if (name == "Iteration$") {
2714  Int_t code = fNcodes++;
2715  fCodes[code] = 0;
2716  fLookupType[code] = kIteration;
2717  return code;
2718  }
2719  if (name == "Length$") {
2720  Int_t code = fNcodes++;
2721  fCodes[code] = 0;
2722  fLookupType[code] = kLength;
2723  return code;
2724  }
2725  static const char *lenfunc = "Length$(";
2726  if (strncmp(name.Data(),"Length$(",strlen(lenfunc))==0
2727  && name[name.Length()-1]==')') {
2728 
2729  TString subform = name.Data()+strlen(lenfunc);
2730  subform.Remove( subform.Length() - 1 );
2731  TTreeFormula *lengthForm = new TTreeFormula("lengthForm",subform,fTree);
2732  fAliases.AddAtAndExpand(lengthForm,fNoper);
2733  Int_t code = fNcodes++;
2734  fCodes[code] = 0;
2735  fLookupType[code] = kLengthFunc;
2736  return code;
2737  }
2738  static const char *minfunc = "Min$(";
2739  if (strncmp(name.Data(),"Min$(",strlen(minfunc))==0
2740  && name[name.Length()-1]==')') {
2741 
2742  TString subform = name.Data()+strlen(minfunc);
2743  subform.Remove( subform.Length() - 1 );
2744  TTreeFormula *minForm = new TTreeFormula("minForm",subform,fTree);
2745  fAliases.AddAtAndExpand(minForm,fNoper);
2746  Int_t code = fNcodes++;
2747  fCodes[code] = 0;
2748  fLookupType[code] = kMin;
2749  return code;
2750  }
2751  static const char *maxfunc = "Max$(";
2752  if (strncmp(name.Data(),"Max$(",strlen(maxfunc))==0
2753  && name[name.Length()-1]==')') {
2754 
2755  TString subform = name.Data()+strlen(maxfunc);
2756  subform.Remove( subform.Length() - 1 );
2757  TTreeFormula *maxForm = new TTreeFormula("maxForm",subform,fTree);
2758  fAliases.AddAtAndExpand(maxForm,fNoper);
2759  Int_t code = fNcodes++;
2760  fCodes[code] = 0;
2761  fLookupType[code] = kMax;
2762  return code;
2763  }
2764  static const char *sumfunc = "Sum$(";
2765  if (strncmp(name.Data(),"Sum$(",strlen(sumfunc))==0
2766  && name[name.Length()-1]==')') {
2767 
2768  TString subform = name.Data()+strlen(sumfunc);
2769  subform.Remove( subform.Length() - 1 );
2770  TTreeFormula *sumForm = new TTreeFormula("sumForm",subform,fTree);
2771  fAliases.AddAtAndExpand(sumForm,fNoper);
2772  Int_t code = fNcodes++;
2773  fCodes[code] = 0;
2774  fLookupType[code] = kSum;
2775  return code;
2776  }
2777 
2778 
2779 
2780  // Check for $Alt(expression1,expression2)
2781  Int_t res = DefineAlternate(name.Data());
2782  if (res!=0) {
2783  // There was either a syntax error or we found $Alt
2784  if (res<0) return res;
2785  action = res;
2786  return 0;
2787  }
2788 
2789  // Find the top level leaf and deal with dimensions
2790 
2791  char cname[kMaxLen]; strlcpy(cname,name.Data(),kMaxLen);
2792  char dims[kMaxLen]; dims[0] = '\0';
2793 
2794  Bool_t final = kFALSE;
2795 
2796  UInt_t paran_level = 0;
2797  TObjArray castqueue;
2798 
2799  // First, it is easier to remove all dimensions information from 'cname'
2800  Int_t cnamelen = strlen(cname);
2801  for(i=0,k=0; i<cnamelen; ++i, ++k) {
2802  if (cname[i] == '[') {
2803  int bracket = i;
2804  int bracket_level = 1;
2805  int j;
2806  for (j=++i; j<cnamelen && (bracket_level>0 || cname[j]=='['); j++, i++) {
2807  if (cname[j]=='[') bracket_level++;
2808  else if (cname[j]==']') bracket_level--;
2809  }
2810  if (bracket_level != 0) {
2811  //Error("DefinedVariable","Bracket unbalanced");
2812  return -1;
2813  }
2814  strncat(dims,&cname[bracket],j-bracket);
2815  //k += j-bracket;
2816  }
2817  if (i!=k) cname[k] = cname[i];
2818  }
2819  cname[k]='\0';
2820 
2821  Bool_t useLeafCollectionObject = kFALSE;
2822  TString leftover;
2823  TLeaf *leaf = 0;
2824  {
2825  std::vector<std::string> aliasSofar = fAliasesUsed;
2826  res = FindLeafForExpression(cname, leaf, leftover, final, paran_level, castqueue, aliasSofar, useLeafCollectionObject, name);
2827  }
2828  if (res<0) return res;
2829 
2830  if (!leaf && res!=2) {
2831  // Check for an alias.
2832  const char *aliasValue = fTree->GetAlias(cname);
2833  if (aliasValue) {
2834  // First check whether we are using this alias recursively (this would
2835  // lead to an infinite recursion.
2836  if (find(fAliasesUsed.begin(),
2837  fAliasesUsed.end(),
2838  cname) != fAliasesUsed.end()) {
2839  Error("DefinedVariable",
2840  "The substitution of the alias \"%s\" by \"%s\" failed\n"\
2841  "\tbecause \"%s\" is recursively used in its own definition!",
2842  cname,aliasValue,cname);
2843  return -3;
2844  }
2845 
2846 
2847  if (strcspn(aliasValue,"+*/-%&!=<>|")!=strlen(aliasValue)) {
2848  // If the alias contains an operator, we need to use a nested formula
2849  // (since DefinedVariable must only add one entry to the operation's list).
2850 
2851  // Need to check the aliases used so far
2852  std::vector<std::string> aliasSofar = fAliasesUsed;
2853  aliasSofar.push_back( cname );
2854 
2855  TString subValue( aliasValue );
2856  if (dims[0]) {
2857  subValue += dims;
2858  }
2859 
2860  TTreeFormula *subform = new TTreeFormula(cname,subValue,fTree,aliasSofar); // Need to pass the aliases used so far.
2861 
2862  if (subform->GetNdim()==0) {
2863  delete subform;
2864  Error("DefinedVariable",
2865  "The substitution of the alias \"%s\" by \"%s\" failed.",cname,aliasValue);
2866  return -3;
2867  }
2868 
2869  fManager->Add(subform);
2870  fAliases.AddAtAndExpand(subform,fNoper);
2871 
2872  if (subform->IsString()) {
2873  action = kAliasString;
2874  return 0;
2875  } else {
2876  action = kAlias;
2877  return 0;
2878  }
2879  } else { /* assumes strcspn(aliasValue,"[]")!=strlen(aliasValue) */
2880  TString thisAlias( aliasValue );
2881  thisAlias += dims;
2882  Int_t aliasRes = DefinedVariable(thisAlias,action);
2883  if (aliasRes<0) {
2884  // We failed but DefinedVariable has not printed why yet.
2885  // and because we want thoses to be printed _before_ the notice
2886  // of the failure of the substitution, we need to print them here.
2887  if (aliasRes==-1) {
2888  Error("Compile", " Bad numerical expression : \"%s\"",thisAlias.Data());
2889  } else if (aliasRes==-2) {
2890  Error("Compile", " Part of the Variable \"%s\" exists but some of it is not accessible or useable",thisAlias.Data());
2891 
2892  }
2893  Error("DefinedVariable",
2894  "The substitution of the alias \"%s\" by \"%s\" failed.",cname,aliasValue);
2895  return -3;
2896  }
2897  return aliasRes;
2898  }
2899  }
2900  }
2901 
2902 
2903  if (leaf || res==2) {
2904 
2905  if (leaf && leaf->GetBranch() && leaf->GetBranch()->TestBit(kDoNotProcess)) {
2906  Error("DefinedVariable","the branch \"%s\" has to be enabled to be used",leaf->GetBranch()->GetName());
2907  return -2;
2908  }
2909 
2910  Int_t code = fNcodes++;
2911 
2912  // If needed will now parse the indexes specified for
2913  // arrays.
2914  if (dims[0]) {
2915  char *current = &( dims[0] );
2916  Int_t dim = 0;
2917  TString varindex;
2918  Int_t index;
2919  Int_t scanindex ;
2920  while (current) {
2921  current++;
2922  if (current[0] == ']') {
2923  fIndexes[code][dim] = -1; // Loop over all elements;
2924  } else {
2925  scanindex = sscanf(current,"%d",&index);
2926  if (scanindex) {
2927  fIndexes[code][dim] = index;
2928  } else {
2929  fIndexes[code][dim] = -2; // Index is calculated via a variable.
2930  varindex = current;
2931  char *end = (char*)(varindex.Data());
2932  for(char bracket_level = 0;*end!=0;end++) {
2933  if (*end=='[') bracket_level++;
2934  if (bracket_level==0 && *end==']') break;
2935  if (*end==']') bracket_level--;
2936  }
2937  *end = '\0';
2938  fVarIndexes[code][dim] = new TTreeFormula("index_var",
2939  varindex,
2940  fTree);
2941  if (fVarIndexes[code][dim]->GetNdim() == 0) {
2942  // Parsing failed for the index, let's stop here ....
2943  return -1;
2944  }
2945  current += strlen(varindex)+1; // move to the end of the index array
2946  }
2947  }
2948  dim ++;
2949  if (dim >= kMAXFORMDIM) {
2950  // NOTE: test that dim this is NOT too big!!
2951  break;
2952  }
2953  current = (char*)strstr( current, "[" );
2954  }
2955  }
2956 
2957  // Now that we have cleaned-up the expression, let's compare it to the content
2958  // of the leaf!
2959 
2960  res = ParseWithLeaf(leaf,leftover,final,paran_level,castqueue,useLeafCollectionObject,name);
2961  if (res<0) return res;
2962  if (res>0) action = res;
2963  return code;
2964  }
2965 
2966 //*-*- May be a graphical cut ?
2967  TCutG *gcut = (TCutG*)gROOT->GetListOfSpecials()->FindObject(name.Data());
2968  if (gcut) {
2969  if (gcut->GetObjectX()) {
2970  if(!gcut->GetObjectX()->InheritsFrom(TTreeFormula::Class())) {
2971  delete gcut->GetObjectX(); gcut->SetObjectX(0);
2972  }
2973  }
2974  if (gcut->GetObjectY()) {
2975  if(!gcut->GetObjectY()->InheritsFrom(TTreeFormula::Class())) {
2976  delete gcut->GetObjectY(); gcut->SetObjectY(0);
2977  }
2978  }
2979 
2980  Int_t code = fNcodes;
2981 
2982  if (strlen(gcut->GetVarX()) && strlen(gcut->GetVarY()) ) {
2983 
2984  TTreeFormula *fx = new TTreeFormula("f_x",gcut->GetVarX(),fTree);
2985  gcut->SetObjectX(fx);
2986 
2987  TTreeFormula *fy = new TTreeFormula("f_y",gcut->GetVarY(),fTree);
2988  gcut->SetObjectY(fy);
2989 
2990  fCodes[code] = -2;
2991 
2992  } else if (strlen(gcut->GetVarX())) {
2993 
2994  // Let's build the equivalent formula:
2995  // min(gcut->X) <= VarX <= max(gcut->Y)
2996  Double_t min = 0;
2997  Double_t max = 0;
2998  Int_t n = gcut->GetN();
2999  Double_t *x = gcut->GetX();
3000  min = max = x[0];
3001  for(Int_t i2 = 1; i2<n; i2++) {
3002  if (x[i2] < min) min = x[i2];
3003  if (x[i2] > max) max = x[i2];
3004  }
3005  TString formula = "(";
3006  formula += min;
3007  formula += "<=";
3008  formula += gcut->GetVarX();
3009  formula += " && ";
3010  formula += gcut->GetVarX();
3011  formula += "<=";
3012  formula += max;
3013  formula += ")";
3014 
3015  TTreeFormula *fx = new TTreeFormula("f_x",formula.Data(),fTree);
3016  gcut->SetObjectX(fx);
3017 
3018  fCodes[code] = -1;
3019 
3020  } else {
3021 
3022  Error("DefinedVariable","Found a TCutG without leaf information (%s)",
3023  gcut->GetName());
3024  return -1;
3025 
3026  }
3027 
3028  fExternalCuts.AddAtAndExpand(gcut,code);
3029  fNcodes++;
3030  fLookupType[code] = -1;
3031  return code;
3032  }
3033 
3034  //may be an entrylist
3035  TEntryList *elist = dynamic_cast<TEntryList*> (gDirectory->Get(name.Data()));
3036  if (elist) {
3037  Int_t code = fNcodes;
3038  fCodes[code] = 0;
3039  fExternalCuts.AddAtAndExpand(elist, code);
3040  fNcodes++;
3041  fLookupType[code] = kEntryList;
3042  return code;
3043 
3044  }
3045 
3046  return -1;
3047 }
3048 
3049 ////////////////////////////////////////////////////////////////////////////////
3050 /// Return the leaf (if any) which contains an object containing
3051 /// a data member which has the name provided in the arguments.
3052 
3053 TLeaf* TTreeFormula::GetLeafWithDatamember(const char* topchoice, const char* nextchoice, Long64_t readentry) const
3054 {
3055  TClass * cl = 0;
3056  TIter nextleaf (fTree->GetIteratorOnAllLeaves());
3057  TFormLeafInfo* clonesinfo = 0;
3058  TLeaf *leafcur;
3059  while ((leafcur = (TLeaf*)nextleaf())) {
3060  // The following code is used somewhere else, we need to factor it out.
3061 
3062  // Here since we are interested in data member, we want to consider only
3063  // 'terminal' branch and leaf.
3064  cl = 0;
3065  if (leafcur->InheritsFrom(TLeafObject::Class()) &&
3066  leafcur->GetBranch()->GetListOfBranches()->Last()==0) {
3067  TLeafObject *lobj = (TLeafObject*)leafcur;
3068  cl = lobj->GetClass();
3069  } else if (leafcur->InheritsFrom(TLeafElement::Class()) && leafcur->IsOnTerminalBranch()) {
3070  TLeafElement * lElem = (TLeafElement*) leafcur;
3071  if (lElem->IsOnTerminalBranch()) {
3072  TBranchElement *branchEl = (TBranchElement *)leafcur->GetBranch();
3073  Int_t type = branchEl->GetStreamerType();
3074  if (type==-1) {
3075  cl = branchEl->GetInfo() ? branchEl->GetInfo()->GetClass() : 0;
3076  } else if (type>60 || type==0) {
3077  // Case of an object data member. Here we allow for the
3078  // variable name to be ommitted. Eg, for Event.root with split
3079  // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
3080  TStreamerElement* element = branchEl->GetInfo()->GetElement(branchEl->GetID());
3081  if (element) cl = element->GetClassPointer();
3082  else cl = 0;
3083  }
3084  }
3085 
3086  }
3087  if (clonesinfo) { delete clonesinfo; clonesinfo = 0; }
3088  if (cl == TClonesArray::Class()) {
3089  // We have a unsplit TClonesArray leaves
3090  // In this case we assume that cl is the class in which the TClonesArray
3091  // belongs.
3092  R__LoadBranch(leafcur->GetBranch(),readentry,fQuickLoad);
3093  TClonesArray * clones;
3094 
3095  TBranch *branch = leafcur->GetBranch();
3096  if ( branch->IsA()==TBranchElement::Class()
3097  && ((TBranchElement*)branch)->GetType()==31) {
3098 
3099  // We have an unsplit TClonesArray as part of a split TClonesArray!
3100 
3101  // Let's not dig any further. If the user really wants a data member
3102  // inside the nested TClonesArray, it has to specify it explicitly.
3103 
3104  continue;
3105 
3106  } else {
3107  Bool_t toplevel = (branch == branch->GetMother());
3108  clonesinfo = new TFormLeafInfoClones(cl, 0, toplevel);
3109  clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leafcur,0);
3110  }
3111  if (clones) cl = clones->GetClass();
3112  } else if (cl && cl->GetCollectionProxy()) {
3113 
3114  // We have a unsplit Collection leaves
3115  // In this case we assume that cl is the class in which the TClonesArray
3116  // belongs.
3117 
3118  TBranch *branch = leafcur->GetBranch();
3119  if ( branch->IsA()==TBranchElement::Class()
3120  && ((TBranchElement*)branch)->GetType()==41) {
3121 
3122  // We have an unsplit Collection as part of a split Collection!
3123 
3124  // Let's not dig any further. If the user really wants a data member
3125  // inside the nested Collection, it has to specify it explicitly.
3126 
3127  continue;
3128 
3129  } else {
3130  clonesinfo = new TFormLeafInfoCollection(cl, 0);
3131  }
3132  cl = cl->GetCollectionProxy()->GetValueClass();
3133  }
3134  if (cl) {
3135  // Now that we have the class, let's check if the topchoice is of its datamember
3136  // or if the nextchoice is a datamember of one of its datamember.
3137  Int_t offset;
3139  TStreamerElement* element = info?info->GetStreamerElement(topchoice,offset):0;
3140  if (!element) {
3141  TIter nextel( cl->GetStreamerInfo()->GetElements() );
3142  TStreamerElement * curelem;
3143  while ((curelem = (TStreamerElement*)nextel())) {
3144 
3145  if (curelem->GetClassPointer() == TClonesArray::Class()) {
3146  // In case of a TClonesArray we need to load the data and read the
3147  // clonesArray object before being able to look into the class inside.
3148  // We need to do that because we are never interested in the TClonesArray
3149  // itself but only in the object inside.
3150  TBranch *branch = leafcur->GetBranch();
3151  TFormLeafInfo *leafinfo = 0;
3152  if (clonesinfo) {
3153  leafinfo = clonesinfo;
3154  } else if (branch->IsA()==TBranchElement::Class()
3155  && ((TBranchElement*)branch)->GetType()==31) {
3156  // Case of a sub branch of a TClonesArray
3157  TBranchElement *branchEl = (TBranchElement*)branch;
3158  TStreamerInfo *bel_info = branchEl->GetInfo();
3159  TClass * mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
3160  TStreamerElement *bel_element =
3161  bel_info->GetElement(branchEl->GetID());
3162  leafinfo = new TFormLeafInfoClones(mother_cl, 0, bel_element, kTRUE);
3163  }
3164 
3165  Int_t clones_offset = 0;
3166  ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),clones_offset);
3167  TFormLeafInfo* sub_clonesinfo = new TFormLeafInfo(cl, clones_offset, curelem);
3168  if (leafinfo)
3169  if (leafinfo->fNext) leafinfo->fNext->fNext = sub_clonesinfo;
3170  else leafinfo->fNext = sub_clonesinfo;
3171  else leafinfo = sub_clonesinfo;
3172 
3173  R__LoadBranch(branch,readentry,fQuickLoad);
3174 
3175  TClonesArray * clones = (TClonesArray*)leafinfo->GetValuePointer(leafcur,0);
3176 
3177  delete leafinfo; clonesinfo = 0;
3178  // If TClonesArray object does not exist we have no information, so let go
3179  // on. This is a weakish test since the TClonesArray object might exist in
3180  // the next entry ... In other word, we ONLY rely on the information available
3181  // in entry #0.
3182  if (!clones) continue;
3183  TClass *sub_cl = clones->GetClass();
3184 
3185  // Now that we finally have the inside class, let's query it.
3186  element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(nextchoice,offset);
3187  if (element) break;
3188  } // if clones array
3189  else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {
3190 
3191  TClass *sub_cl = curelem->GetClassPointer()->GetCollectionProxy()->GetValueClass();
3192 
3193  while(sub_cl && sub_cl->GetCollectionProxy())
3194  sub_cl = sub_cl->GetCollectionProxy()->GetValueClass();
3195 
3196  // Now that we finally have the inside class, let's query it.
3197  if (sub_cl) element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(nextchoice,offset);
3198  if (element) break;
3199 
3200  }
3201  } // loop on elements
3202  }
3203  if (element) break;
3204  else cl = 0;
3205  }
3206  }
3207  delete clonesinfo;
3208  if (cl) {
3209  return leafcur;
3210  } else {
3211  return 0;
3212  }
3213 }
3214 
3215 ////////////////////////////////////////////////////////////////////////////////
3216 /// Return the leaf (if any) of the tree with contains an object of a class
3217 /// having a method which has the name provided in the argument.
3218 
3219 Bool_t TTreeFormula::BranchHasMethod(TLeaf* leafcur, TBranch* branch, const char* method, const char* params, Long64_t readentry) const
3220 {
3221  TClass *cl = 0;
3222  TLeafObject* lobj = 0;
3223 
3224  // Since the user does not want this branch to be loaded anyway, we just
3225  // skip it. This prevents us from warning the user that the method might
3226  // be on a disabled branch. However, and more usefully, this allows the
3227  // user to avoid error messages from branches that cannot be currently
3228  // read without warnings/errors.
3229 
3230  if (branch->TestBit(kDoNotProcess)) {
3231  return kFALSE;
3232  }
3233 
3234  // FIXME: The following code is used somewhere else, we need to factor it out.
3235  if (branch->InheritsFrom(TBranchObject::Class())) {
3236  lobj = (TLeafObject*) branch->GetListOfLeaves()->At(0);
3237  cl = lobj->GetClass();
3238  } else if (branch->InheritsFrom(TBranchElement::Class())) {
3239  TBranchElement* branchEl = (TBranchElement*) branch;
3240  Int_t type = branchEl->GetStreamerType();
3241  if (type == -1) {
3242  cl = branchEl->GetInfo() ? branchEl->GetInfo()->GetClass() : 0;
3243  } else if (type > 60) {
3244  // Case of an object data member. Here we allow for the
3245  // variable name to be ommitted. Eg, for Event.root with split
3246  // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
3247  TStreamerElement* element = branchEl->GetInfo()->GetElement(branchEl->GetID());
3248  if (element) {
3249  cl = element->GetClassPointer();
3250  } else {
3251  cl = 0;
3252  }
3253  if ((cl == TClonesArray::Class()) && (branchEl->GetType() == 31)) {
3254  // we have a TClonesArray inside a split TClonesArray,
3255  // Let's not dig any further. If the user really wants a data member
3256  // inside the nested TClonesArray, it has to specify it explicitly.
3257  cl = 0;
3258  }
3259  // NOTE do we need code for Collection here?
3260  }
3261  }
3262 
3263  if (cl == TClonesArray::Class()) {
3264  // We might be try to call a method of the top class inside a
3265  // TClonesArray.
3266  // Since the leaf was not terminal, we might have a split or
3267  // unsplit and/or top leaf/branch.
3268  TClonesArray* clones = 0;
3269  R__LoadBranch(branch, readentry, fQuickLoad);
3270  if (branch->InheritsFrom(TBranchObject::Class())) {
3271  clones = (TClonesArray*) lobj->GetObject();
3272  } else if (branch->InheritsFrom(TBranchElement::Class())) {
3273  // We do not know exactly where the leaf of the TClonesArray is
3274  // in the hierachy but we still need to get the correct class
3275  // holder.
3276  TBranchElement* bc = (TBranchElement*) branch;
3277  if (bc == bc->GetMother()) {
3278  // Top level branch
3279  //clones = *((TClonesArray**) bc->GetAddress());
3280  clones = (TClonesArray*) bc->GetObject();
3281  } else if (!leafcur || !leafcur->IsOnTerminalBranch()) {
3282  TStreamerElement* element = bc->GetInfo()->GetElement(bc->GetID());
3283  if (element->IsaPointer()) {
3284  clones = *((TClonesArray**) bc->GetAddress());
3285  //clones = *((TClonesArray**) bc->GetObject());
3286  } else {
3287  //clones = (TClonesArray*) bc->GetAddress();
3288  clones = (TClonesArray*) bc->GetObject();
3289  }
3290  }
3291  if (!clones) {
3292  R__LoadBranch(bc, readentry, fQuickLoad);
3293  TClass* mother_cl;
3294  mother_cl = bc->GetInfo()->GetClass();
3295  TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0);
3296  // if (!leafcur) { leafcur = (TLeaf*) branch->GetListOfLeaves()->At(0); }
3297  clones = (TClonesArray*) clonesinfo->GetLocalValuePointer(leafcur, 0);
3298  // cl = clones->GetClass();
3299  delete clonesinfo;
3300  }
3301  } else {
3302  Error("BranchHasMethod","A TClonesArray was stored in a branch type no yet support (i.e. neither TBranchObject nor TBranchElement): %s",branch->IsA()->GetName());
3303  return kFALSE;
3304  }
3305  cl = clones ? clones->GetClass() : 0;
3306  } else if (cl && cl->GetCollectionProxy()) {
3307  cl = cl->GetCollectionProxy()->GetValueClass();
3308  }
3309 
3310  if (cl) {
3311  if (cl->GetClassInfo()) {
3312  if (cl->GetMethodAllAny(method)) {
3313  // Let's try to see if the function we found belongs to the current
3314  // class. Note that this implementation currently can not work if
3315  // one the argument is another leaf or data member of the object.
3316  // (Anyway we do NOT support this case).
3317  TMethodCall methodcall(cl, method, params);
3318  if (methodcall.GetMethod()) {
3319  // We have a method that works.
3320  // We will use it.
3321  return kTRUE;
3322  }
3323  }
3324  }
3325  }
3326 
3327  return kFALSE;
3328 }
3329 
3330 ////////////////////////////////////////////////////////////////////////////////
3331 /// Now let calculate what physical instance we really need.
3332 /// Some redundant code is used to speed up the cases where
3333 /// they are no dimensions.
3334 ///
3335 /// We know that instance is less that fCumulUsedSize[0] so
3336 /// we can skip the modulo when virt_dim is 0.
3337 
3339  Int_t real_instance = 0;
3340  Int_t virt_dim;
3341 
3342  Bool_t check = kFALSE;
3343  if (codeindex<0) {
3344  codeindex = 0;
3345  check = kTRUE;
3346  }
3347 
3348  TFormLeafInfo * info = 0;
3349  Int_t max_dim = fNdimensions[codeindex];
3350  if ( max_dim ) {
3351  virt_dim = 0;
3352  max_dim--;
3353 
3354  if (!fManager->fMultiVarDim) {
3355  if (fIndexes[codeindex][0]>=0) {
3356  real_instance = fIndexes[codeindex][0] * fCumulSizes[codeindex][1];
3357  } else {
3358  Int_t local_index;
3359  local_index = ( instance / fManager->fCumulUsedSizes[virt_dim+1]);
3360  if (fIndexes[codeindex][0]==-2) {
3361  // NOTE: Should we check that this is a valid index?
3362  if (check) {
3363  Int_t index_real_instance = fVarIndexes[codeindex][0]->GetRealInstance(local_index,-1);
3364  if (index_real_instance >= fVarIndexes[codeindex][0]->fNdata[0]) {
3365  // out of bounds
3366  return fNdata[0]+1;
3367  }
3368  }
3369  if (fDidBooleanOptimization && local_index!=0) {
3370  // Force the loading of the index.
3371  fVarIndexes[codeindex][0]->LoadBranches();
3372  }
3373  local_index = (Int_t)fVarIndexes[codeindex][0]->EvalInstance(local_index);
3374  if (local_index<0) {
3375  Error("EvalInstance","Index %s is out of bound (%d) in formula %s",
3376  fVarIndexes[codeindex][0]->GetTitle(),
3377  local_index,
3378  GetTitle());
3379  return fNdata[0]+1;
3380  }
3381  }
3382  real_instance = local_index * fCumulSizes[codeindex][1];
3383  virt_dim ++;
3384  }
3385  } else {
3386  // NOTE: We assume that ONLY the first dimension of a leaf can have a variable
3387  // size AND contain the index for the size of yet another sub-dimension.
3388  // I.e. a variable size array inside a variable size array can only have its
3389  // size vary with the VERY FIRST physical dimension of the leaf.
3390  // Thus once the index of the first dimension is found, all other dimensions
3391  // are fixed!
3392 
3393  // NOTE: We could unroll some of this loops to avoid a few tests.
3394  if (fHasMultipleVarDim[codeindex]) {
3395  info = (TFormLeafInfo *)(fDataMembers.At(codeindex));
3396  // if (info && info->GetVarDim()==-1) info = 0;
3397  }
3398  Int_t local_index;
3399 
3400  switch (fIndexes[codeindex][0]) {
3401  case -2:
3402  if (fDidBooleanOptimization && instance!=0) {
3403  // Force the loading of the index.
3404  fVarIndexes[codeindex][0]->LoadBranches();
3405  }
3406  local_index = (Int_t)fVarIndexes[codeindex][0]->EvalInstance(instance);
3407  if (local_index<0) {
3408  Error("EvalInstance","Index %s is out of bound (%d) in formula %s",
3409  fVarIndexes[codeindex][0]->GetTitle(),
3410  local_index,
3411  GetTitle());
3412  local_index = 0;
3413  }
3414  break;
3415  case -1: {
3416  if (instance <= fRealInstanceCache.fInstanceCache) {
3419  }
3421  local_index = fRealInstanceCache.fLocalIndexCache;
3423 
3424  Int_t maxloop = fManager->fCumulUsedVarDims->GetSize();
3425  if (maxloop == 0) {
3426  local_index--;
3427  instance = fNdata[0]+1; // out of bounds.
3428  if (check) return fNdata[0]+1;
3429  } else {
3430  do {
3431  virt_accum += fManager->fCumulUsedVarDims->GetArray()[local_index];
3432  local_index++;
3433  } while( instance >= virt_accum && local_index<maxloop);
3434  local_index--;
3435  // update the cache
3436  fRealInstanceCache.fVirtAccumCache = virt_accum - fManager->fCumulUsedVarDims->GetArray()[local_index];
3437  fRealInstanceCache.fLocalIndexCache = local_index;
3438 
3439  if (local_index==(maxloop-1) && (instance >= virt_accum)) {
3440  instance = fNdata[0]+1; // out of bounds.
3441  if (check) return fNdata[0]+1;
3442  } else {
3443  if (fManager->fCumulUsedVarDims->At(local_index)) {
3444  instance -= (virt_accum - fManager->fCumulUsedVarDims->At(local_index));
3445  } else {
3446  instance = fNdata[0]+1; // out of bounds.
3447  if (check) return fNdata[0]+1;
3448  }
3449  }
3450  }
3451  virt_dim ++;
3452  }
3453  break;
3454  default:
3455  local_index = fIndexes[codeindex][0];
3456  }
3457 
3458  // Inform the (appropriate) MultiVarLeafInfo that the clones array index is
3459  // local_index.
3460 
3461  if (fManager->fVarDims[kMAXFORMDIM]) {
3463  } else {
3465  }
3466  for(Int_t d = kMAXFORMDIM-1; d>0; d--) {
3467  if (fManager->fVarDims[d]) {
3469  } else {
3471  }
3472  }
3473  if (info) {
3474  // When we have multiple variable dimensions, the LeafInfo only expect
3475  // the instance after the primary index has been set.
3476  info->SetPrimaryIndex(local_index);
3477  real_instance = 0;
3478 
3479  // Let's update fCumulSizes for the rest of the code.
3480  Int_t vdim = info->GetVarDim();
3481  Int_t isize = info->GetSize(local_index);
3482  if (fIndexes[codeindex][vdim]>=0) {
3483  info->SetSecondaryIndex(fIndexes[codeindex][vdim]);
3484  }
3485  if (isize!=1 && fIndexes[codeindex][vdim]>isize) {
3486  // We are out of bounds!
3487  return fNdata[0]+1;
3488  }
3489  fCumulSizes[codeindex][vdim] = isize*fCumulSizes[codeindex][vdim+1];
3490  for(Int_t k=vdim -1; k>0; --k) {
3491  fCumulSizes[codeindex][k] = fCumulSizes[codeindex][k+1]*fFixedSizes[codeindex][k];
3492  }
3493  } else {
3494  real_instance = local_index * fCumulSizes[codeindex][1];
3495  }
3496  }
3497  if (max_dim>0) {
3498  for (Int_t dim = 1; dim < max_dim; dim++) {
3499  if (fIndexes[codeindex][dim]>=0) {
3500  real_instance += fIndexes[codeindex][dim] * fCumulSizes[codeindex][dim+1];
3501  } else {
3502  Int_t local_index;
3503  if (virt_dim && fManager->fCumulUsedSizes[virt_dim]>1) {
3504  local_index = ( ( instance % fManager->fCumulUsedSizes[virt_dim] )
3505  / fManager->fCumulUsedSizes[virt_dim+1]);
3506  } else {
3507  local_index = ( instance / fManager->fCumulUsedSizes[virt_dim+1]);
3508  }
3509  if (fIndexes[codeindex][dim]==-2) {
3510  // NOTE: Should we check that this is a valid index?
3511  if (fDidBooleanOptimization && local_index!=0) {
3512  // Force the loading of the index.
3513  fVarIndexes[codeindex][dim]->LoadBranches();
3514  }
3515  local_index = (Int_t)fVarIndexes[codeindex][dim]->EvalInstance(local_index);
3516  if (local_index<0 ||
3517  local_index>=(fCumulSizes[codeindex][dim]/fCumulSizes[codeindex][dim+1])) {
3518  Error("EvalInstance","Index %s is out of bound (%d/%d) in formula %s",
3519  fVarIndexes[codeindex][dim]->GetTitle(),
3520  local_index,
3521  (fCumulSizes[codeindex][dim]/fCumulSizes[codeindex][dim+1]),
3522  GetTitle());
3523  local_index = (fCumulSizes[codeindex][dim]/fCumulSizes[codeindex][dim+1])-1;
3524  }
3525  }
3526  real_instance += local_index * fCumulSizes[codeindex][dim+1];
3527  virt_dim ++;
3528  }
3529  }
3530  if (fIndexes[codeindex][max_dim]>=0) {
3531  if (!info) real_instance += fIndexes[codeindex][max_dim];
3532  } else {
3533  Int_t local_index;
3534  if (virt_dim && fManager->fCumulUsedSizes[virt_dim]>1) {
3535  local_index = instance % fManager->fCumulUsedSizes[virt_dim];
3536  } else {
3537  local_index = instance;
3538  }
3539  if (info && local_index>=fCumulSizes[codeindex][max_dim]) {
3540  // We are out of bounds! [Multiple var dims, See same message a few line above]
3541  return fNdata[0]+1;
3542  }
3543  if (fIndexes[codeindex][max_dim]==-2) {
3544  if (fDidBooleanOptimization && local_index!=0) {
3545  // Force the loading of the index.
3546  fVarIndexes[codeindex][max_dim]->LoadBranches();
3547  }
3548  local_index = (Int_t)fVarIndexes[codeindex][max_dim]->EvalInstance(local_index);
3549  if (local_index<0 ||
3550  local_index>=fCumulSizes[codeindex][max_dim]) {
3551  Error("EvalInstance","Index %s is of out bound (%d/%d) in formula %s",
3552  fVarIndexes[codeindex][max_dim]->GetTitle(),
3553  local_index,
3554  fCumulSizes[codeindex][max_dim],
3555  GetTitle());
3556  local_index = fCumulSizes[codeindex][max_dim]-1;
3557  }
3558  }
3559  real_instance += local_index;
3560  }
3561  } // if (max_dim-1>0)
3562  } // if (max_dim)
3563 
3564  return real_instance;
3565 }
3566 
3567 ////////////////////////////////////////////////////////////////////////////////
3568 /// Evaluate the class of this treeformula.
3569 ///
3570 /// If the 'value' of this formula is a simple pointer to an object,
3571 /// this function returns the TClass corresponding to its type.
3572 
3574 {
3575  if (fNoper != 1 || fNcodes <=0 ) return 0;
3576 
3577  return EvalClass(0);
3578 }
3579 
3580 ////////////////////////////////////////////////////////////////////////////////
3581 /// Evaluate the class of the operation oper.
3582 ///
3583 /// If the 'value' in the requested operation is a simple pointer to an object,
3584 /// this function returns the TClass corresponding to its type.
3585 
3587 {
3588  TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(oper);
3589  switch(fLookupType[oper]) {
3590  case kDirect: {
3591  if (leaf->IsA()==TLeafObject::Class()) {
3592  return ((TLeafObject*)leaf)->GetClass();
3593  } else if ( leaf->IsA()==TLeafElement::Class()) {
3594  TBranchElement * branch = (TBranchElement*)((TLeafElement*)leaf)->GetBranch();
3595  TStreamerInfo * info = branch->GetInfo();
3596  Int_t id = branch->GetID();
3597  if (id>=0) {
3598  if (info==0 || !info->IsCompiled()) {
3599  // we probably do not have a way to know the class of the object.
3600  return 0;
3601  }
3602  TStreamerElement* elem = (TStreamerElement*)info->GetElement(id);
3603  if (elem==0) {
3604  // we probably do not have a way to know the class of the object.
3605  return 0;
3606  } else {
3607  return elem->GetClass();
3608  }
3609  } else return TClass::GetClass( branch->GetClassName() );
3610  } else {
3611  return 0;
3612  }
3613  }
3614  case kMethod: return 0; // kMethod is deprecated so let's no waste time implementing this.
3615  case kTreeMember:
3616  case kDataMember: {
3617  TObject *obj = fDataMembers.UncheckedAt(oper);
3618  if (!obj) return 0;
3619  return ((TFormLeafInfo*)obj)->GetClass();
3620  }
3621 
3622  default: return 0;
3623  }
3624 
3625 
3626 }
3627 
3628 ////////////////////////////////////////////////////////////////////////////////
3629 /// Evaluate this treeformula.
3630 ///
3631 /// Return the address of the object pointed to by the formula.
3632 /// Return 0 if the formula is not a single object
3633 /// The object type can be retrieved using by call EvalClass();
3634 
3635 void* TTreeFormula::EvalObject(int instance)
3636 {
3637  if (fNoper != 1 || fNcodes <=0 ) return 0;
3638 
3639 
3640  switch (fLookupType[0]) {
3641  case kIndexOfEntry:
3642  case kIndexOfLocalEntry:
3643  case kEntries:
3644  case kLocalEntries:
3645  case kLength:
3646  case kLengthFunc:
3647  case kIteration:
3648  case kEntryList:
3649  return 0;
3650  }
3651 
3652  TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);
3653 
3654  Int_t real_instance = GetRealInstance(instance,0);
3655 
3656  if (instance==0 || fNeedLoading) {
3657  fNeedLoading = kFALSE;
3658  R__LoadBranch(leaf->GetBranch(),
3659  leaf->GetBranch()->GetTree()->GetReadEntry(),
3660  fQuickLoad);
3661  }
3662  else if (real_instance>=fNdata[0]) return 0;
3663  if (fAxis) {
3664  return 0;
3665  }
3666  switch(fLookupType[0]) {
3667  case kDirect: {
3668  if (real_instance) {
3669  Warning("EvalObject","Not yet implement for kDirect and arrays (for %s).\nPlease contact the developers",GetName());
3670  }
3671  return leaf->GetValuePointer();
3672  }
3673  case kMethod: return GetValuePointerFromMethod(0,leaf);
3674  case kTreeMember:
3675  case kDataMember: return ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->GetValuePointer(leaf,real_instance);
3676  default: return 0;
3677  }
3678 
3679 
3680 }
3681 
3682 
3683 ////////////////////////////////////////////////////////////////////////////////
3684 /// Eval the instance as a string.
3685 
3687 {
3688  const Int_t kMAXSTRINGFOUND = 10;
3689  const char *stringStack[kMAXSTRINGFOUND];
3690 
3691  if (fNoper==1 && fNcodes>0 && IsString()) {
3692  TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);
3693 
3694  Int_t real_instance = GetRealInstance(instance,0);
3695 
3696  if (instance==0 || fNeedLoading) {
3697  fNeedLoading = kFALSE;
3698  TBranch *branch = leaf->GetBranch();
3699  R__LoadBranch(branch,branch->GetTree()->GetReadEntry(),fQuickLoad);
3700  } else if (real_instance>=fNdata[0]) {
3701  return 0;
3702  }
3703 
3704  if (fLookupType[0]==kDirect) {
3705  return (char*)leaf->GetValuePointer();
3706  } else {
3707  return (char*)GetLeafInfo(0)->GetValuePointer(leaf,real_instance);
3708  }
3709  }
3710 
3711  EvalInstance(instance,stringStack);
3712 
3713  return stringStack[0];
3714 }
3715 
3716 #define TT_EVAL_INIT \
3717  TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0); \
3718  \
3719  const Int_t real_instance = GetRealInstance(instance,0); \
3720  \
3721  if (instance==0) fNeedLoading = kTRUE; \
3722  if (real_instance>=fNdata[0]) return 0; \
3723  \
3724  /* Since the only operation in this formula is reading this branch, \
3725  we are guaranteed that this function is first called with instance==0 and \
3726  hence we are guaranteed that the branch is always properly read */ \
3727  \
3728  if (fNeedLoading) { \
3729  fNeedLoading = kFALSE; \
3730  TBranch *br = leaf->GetBranch(); \
3731  Long64_t tentry = br->GetTree()->GetReadEntry(); \
3732  R__LoadBranch(br,tentry,fQuickLoad); \
3733  } \
3734  \
3735  if (fAxis) { \
3736  char * label; \
3737  /* This portion is a duplicate (for speed reason) of the code \
3738  located in the main for loop at "a tree string" (and in EvalStringInstance) */ \
3739  if (fLookupType[0]==kDirect) { \
3740  label = (char*)leaf->GetValuePointer(); \
3741  } else { \
3742  label = (char*)GetLeafInfo(0)->GetValuePointer(leaf,instance); \
3743  } \
3744  Int_t bin = fAxis->FindBin(label); \
3745  return bin-0.5; \
3746  }
3747 
3748 #define TREE_EVAL_INIT \
3749  const Int_t real_instance = GetRealInstance(instance,0); \
3750  \
3751  if (real_instance>=fNdata[0]) return 0; \
3752  \
3753  if (fAxis) { \
3754  char * label; \
3755  /* This portion is a duplicate (for speed reason) of the code \
3756  located in the main for loop at "a tree string" (and in EvalStringInstance) */ \
3757  label = (char*)GetLeafInfo(0)->GetValuePointer((TLeaf*)0x0,instance); \
3758  Int_t bin = fAxis->FindBin(label); \
3759  return bin-0.5; \
3760  }
3761 
3762 #define TT_EVAL_INIT_LOOP \
3763  TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(code); \
3764  \
3765  /* Now let calculate what physical instance we really need. */ \
3766  const Int_t real_instance = GetRealInstance(instance,code); \
3767  \
3768  if (willLoad) { \
3769  TBranch *branch = (TBranch*)fBranches.UncheckedAt(code); \
3770  if (branch) { \
3771  Long64_t treeEntry = branch->GetTree()->GetReadEntry(); \
3772  R__LoadBranch(branch,treeEntry,fQuickLoad); \
3773  } else if (fDidBooleanOptimization) { \
3774  branch = leaf->GetBranch(); \
3775  Long64_t treeEntry = branch->GetTree()->GetReadEntry(); \
3776  if (branch->GetReadEntry() != treeEntry) branch->GetEntry( treeEntry ); \
3777  } \
3778  } else { \
3779  /* In the cases where we are behind (i.e. right of) a potential boolean optimization \
3780  this tree variable reading may have not been executed with instance==0 which would \
3781  result in the branch being potentially not read in. */ \
3782  if (fDidBooleanOptimization) { \
3783  TBranch *br = leaf->GetBranch(); \
3784  Long64_t treeEntry = br->GetTree()->GetReadEntry(); \
3785  if (br->GetReadEntry() != treeEntry) br->GetEntry( treeEntry ); \
3786  } \
3787  } \
3788  if (real_instance>=fNdata[code]) return 0;
3789 
3790 #define TREE_EVAL_INIT_LOOP \
3791  /* Now let calculate what physical instance we really need. */ \
3792  const Int_t real_instance = GetRealInstance(instance,code); \
3793  \
3794  if (real_instance>=fNdata[code]) return 0;
3795 
3796 
3797 template<typename T> T Summing(TTreeFormula *sum) {
3798  Int_t len = sum->GetNdata();
3799  T res = 0;
3800  for (int i=0; i<len; ++i) res += sum->EvalInstance<T>(i);
3801  return res;
3802 }
3803 
3804 template<typename T> T FindMin(TTreeFormula *arr) {
3805  Int_t len = arr->GetNdata();
3806  T res = 0;
3807  if (len) {
3808  res = arr->EvalInstance<T>(0);
3809  for (int i=1; i<len; ++i) {
3810  T val = arr->EvalInstance<T>(i);
3811  if (val < res) {
3812  res = val;
3813  }
3814  }
3815  }
3816  return res;
3817 }
3818 
3819 template<typename T> T FindMax(TTreeFormula *arr) {
3820  Int_t len = arr->GetNdata();
3821  T res = 0;
3822  if (len) {
3823  res = arr->EvalInstance<T>(0);
3824  for (int i=1; i<len; ++i) {
3825  T val = arr->EvalInstance(i);
3826  if (val > res) {
3827  res = val;
3828  }
3829  }
3830  }
3831  return res;
3832 }
3833 
3834 template<typename T> T FindMin(TTreeFormula *arr, TTreeFormula *condition) {
3835  Int_t len = arr->GetNdata();
3836  T res = 0;
3837  if (len) {
3838  int i = 0;
3839  T condval;
3840  do {
3841  condval = condition->EvalInstance<T>(i);
3842  ++i;
3843  } while (!condval && i<len);
3844  if (!condval && i==len) {
3845  return 0;
3846  }
3847  if (i!=1) {
3848  // Insure the loading of the branch.
3849  arr->EvalInstance<T>(0);
3850  }
3851  // Now we know that i>0 && i<len and cond==true
3852  res = arr->EvalInstance<T>(i-1);
3853  for (; i<len; ++i) {
3854  condval = condition->EvalInstance<T>(i);
3855  if (condval) {
3856  T val = arr->EvalInstance<T>(i);
3857  if (val < res) {
3858  res = val;
3859  }
3860  }
3861  }
3862  }
3863  return res;
3864 }
3865 
3866 template<typename T> T FindMax(TTreeFormula *arr, TTreeFormula *condition) {
3867  Int_t len = arr->GetNdata();
3868  T res = 0;
3869  if (len) {
3870  int i = 0;
3871  T condval;
3872  do {
3873  condval = condition->EvalInstance<T>(i);
3874  ++i;
3875  } while (!condval && i<len);
3876  if (!condval && i==len) {
3877  return 0;
3878  }
3879  if (i!=1) {
3880  // Insure the loading of the branch.
3881  arr->EvalInstance<T>(0);
3882  }
3883  // Now we know that i>0 && i<len and cond==true
3884  res = arr->EvalInstance<T>(i-1);
3885  for (; i<len; ++i) {
3886  condval = condition->EvalInstance<T>(i);
3887  if (condval) {
3888  T val = arr->EvalInstance<T>(i);
3889  if (val > res) {
3890  res = val;
3891  }
3892  }
3893  }
3894  }
3895  return res;
3896 }
3897 
3898 namespace {
3899 
3900 template <typename T> T fmod_local(T x, T y) { return fmod(x,y); }
3901 template <> Long64_t fmod_local(Long64_t x, Long64_t y) { return fmod((LongDouble_t)x,(LongDouble_t)y); }
3902 
3903 template<typename T> inline void SetMethodParam(TMethodCall *method, T p) { method->SetParam(p); }
3904 template<> void SetMethodParam(TMethodCall *method, LongDouble_t p) { method->SetParam((Double_t)p); }
3905 
3906 }
3907 
3908 template<typename T> inline T TTreeFormula::GetConstant(Int_t k) { return fConst[k]; }
3910  if( !fConstLD ) {
3911  // create LD version of the constants list by rescanning all literals used in the expression
3912  fConstLD = new LongDouble_t[fNconst];
3913  for (Int_t op=0; op<fNoper ; ++op) {
3914  const Int_t oper = GetOper()[op];
3915  if( (oper >> kTFOperShift) == kConstant ) {
3916  int i = (oper & kTFOperMask);
3917  if( !strncmp(fExpr[op], "0x", 2) || !strncmp(fExpr[op], "0X", 2) ) {
3918  ULong64_t val;
3919  sscanf( fExpr[op], "%llx", &val );
3920  fConstLD[i] = (LongDouble_t)val;
3921  } else {
3922  sscanf( fExpr[op], "%Lg", &fConstLD[i] );
3923  }
3924  }
3925  }
3926  }
3927  return fConstLD[k];
3928 }
3929 template<> inline Long64_t TTreeFormula::GetConstant(Int_t k) { return (Long64_t)GetConstant<LongDouble_t>(k); }
3930 
3931 ////////////////////////////////////////////////////////////////////////////////
3932 /// Evaluate this treeformula.
3933 
3934 template<typename T>
3935 T TTreeFormula::EvalInstance(Int_t instance, const char *stringStackArg[])
3936 {
3937 // Note that the redundance and structure in this code is tailored to improve
3938 // efficiencies.
3939  if (TestBit(kMissingLeaf)) return 0;
3940  if (fNoper == 1 && fNcodes > 0) {
3941 
3942  switch (fLookupType[0]) {
3943  case kDirect: {
3944  TT_EVAL_INIT;
3945  return leaf->GetTypedValue<T>(real_instance);
3946  }
3947  case kMethod: {
3948  TT_EVAL_INIT;
3949  ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->SetBranch(leaf->GetBranch());
3950  return GetValueFromMethod(0,leaf);
3951  }
3952  case kDataMember: {
3953  TT_EVAL_INIT;
3954  ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->SetBranch(leaf->GetBranch());
3955  return ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->GetTypedValue<T>(leaf,real_instance);
3956  }
3957  case kTreeMember: {
3959  return ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->GetTypedValue<T>((TLeaf*)0x0,real_instance);
3960  }
3961  case kIndexOfEntry: return (T)fTree->GetReadEntry();
3962  case kIndexOfLocalEntry: return (T)fTree->GetTree()->GetReadEntry();
3963  case kEntries: return (T)fTree->GetEntries();
3964  case kLocalEntries: return (T)fTree->GetTree()->GetEntries();
3965  case kLength: return fManager->fNdata;
3966  case kLengthFunc: return ((TTreeFormula*)fAliases.UncheckedAt(0))->GetNdata();
3967  case kIteration: return instance;
3968  case kSum: return Summing<T>((TTreeFormula*)fAliases.UncheckedAt(0));
3969  case kMin: return FindMin<T>((TTreeFormula*)fAliases.UncheckedAt(0));
3970  case kMax: return FindMax<T>((TTreeFormula*)fAliases.UncheckedAt(0));
3971  case kEntryList: {
3972  TEntryList *elist = (TEntryList*)fExternalCuts.At(0);
3973  return elist->Contains(fTree->GetTree()->GetReadEntry());
3974  }
3975  case -1: break;
3976  }
3977  switch (fCodes[0]) {
3978  case -2: {
3979  TCutG *gcut = (TCutG*)fExternalCuts.At(0);
3980  TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
3981  TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
3982  T xcut = fx->EvalInstance<T>(instance);
3983  T ycut = fy->EvalInstance<T>(instance);
3984  return gcut->IsInside(xcut,ycut);
3985  }
3986  case -1: {
3987  TCutG *gcut = (TCutG*)fExternalCuts.At(0);
3988  TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
3989  return fx->EvalInstance<T>(instance);
3990  }
3991  default: return 0;
3992  }
3993  }
3994 
3995  T tab[kMAXFOUND];
3996  const Int_t kMAXSTRINGFOUND = 10;
3997  const char *stringStackLocal[kMAXSTRINGFOUND];
3998  const char **stringStack = stringStackArg?stringStackArg:stringStackLocal;
3999 
4000  const Bool_t willLoad = (instance==0 || fNeedLoading); fNeedLoading = kFALSE;
4001  if (willLoad) fDidBooleanOptimization = kFALSE;
4002 
4003  Int_t pos = 0;
4004  Int_t pos2 = 0;
4005  for (Int_t i=0; i<fNoper ; ++i) {
4006 
4007  const Int_t oper = GetOper()[i];
4008  const Int_t newaction = oper >> kTFOperShift;
4009 
4010  if (newaction<kDefinedVariable) {
4011  // ROOT::v5::TFormula operands.
4012 
4013  // one of the most used cases
4014  if (newaction==kConstant) { pos++; tab[pos-1] = GetConstant<T>(oper & kTFOperMask); continue; }
4015 
4016  switch(newaction) {
4017 
4018  case kEnd : return tab[0];
4019  case kAdd : pos--; tab[pos-1] += tab[pos]; continue;
4020  case kSubstract : pos--; tab[pos-1] -= tab[pos]; continue;
4021  case kMultiply : pos--; tab[pos-1] *= tab[pos]; continue;
4022  case kDivide : pos--; if (tab[pos] == 0) tab[pos-1] = 0; // division by 0
4023  else tab[pos-1] /= tab[pos];
4024  continue;
4025  case kModulo : {pos--;
4026  Long64_t int1((Long64_t)tab[pos-1]);
4027  Long64_t int2((Long64_t)tab[pos]);
4028  tab[pos-1] = T(int1 % int2);
4029  continue;}
4030 
4031  case kcos : tab[pos-1] = TMath::Cos(tab[pos-1]); continue;
4032  case ksin : tab[pos-1] = TMath::Sin(tab[pos-1]); continue;
4033  case ktan : if (TMath::Cos(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
4034  else tab[pos-1] = TMath::Tan(tab[pos-1]);
4035  continue;
4036  case kacos : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
4037  else tab[pos-1] = TMath::ACos(tab[pos-1]);
4038  continue;
4039  case kasin : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
4040  else tab[pos-1] = TMath::ASin(tab[pos-1]);
4041  continue;
4042  case katan : tab[pos-1] = TMath::ATan(tab[pos-1]); continue;
4043  case kcosh : tab[pos-1] = TMath::CosH(tab[pos-1]); continue;
4044  case ksinh : tab[pos-1] = TMath::SinH(tab[pos-1]); continue;
4045  case ktanh : if (TMath::CosH(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
4046  else tab[pos-1] = TMath::TanH(tab[pos-1]);
4047  continue;
4048  case kacosh: if (tab[pos-1] < 1) {tab[pos-1] = 0;} // indetermination
4049  else tab[pos-1] = TMath::ACosH(tab[pos-1]);
4050  continue;
4051  case kasinh: tab[pos-1] = TMath::ASinH(tab[pos-1]); continue;
4052  case katanh: if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
4053  else tab[pos-1] = TMath::ATanH(tab[pos-1]);
4054  continue;
4055  case katan2: pos--; tab[pos-1] = TMath::ATan2(tab[pos-1],tab[pos]); continue;
4056 
4057  case kfmod : pos--; tab[pos-1] = fmod_local(tab[pos-1],tab[pos]); continue;
4058  case kpow : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
4059  case ksq : tab[pos-1] = tab[pos-1]*tab[pos-1]; continue;
4060  case ksqrt : tab[pos-1] = TMath::Sqrt(TMath::Abs(tab[pos-1])); continue;
4061 
4062  case kstrstr : pos2 -= 2; pos++;if (strstr(stringStack[pos2],stringStack[pos2+1])) tab[pos-1]=1;
4063  else tab[pos-1]=0;
4064  continue;
4065 
4066  case kmin : pos--; tab[pos-1] = std::min(tab[pos-1],tab[pos]); continue;
4067  case kmax : pos--; tab[pos-1] = std::max(tab[pos-1],tab[pos]); continue;
4068 
4069  case klog : if (tab[pos-1] > 0) tab[pos-1] = TMath::Log(tab[pos-1]);
4070  else {tab[pos-1] = 0;} //{indetermination }
4071  continue;
4072  case kexp : { Double_t dexp = tab[pos-1];
4073  if (dexp < -700) {tab[pos-1] = 0; continue;}
4074  if (dexp > 700) {tab[pos-1] = TMath::Exp(700); continue;}
4075  tab[pos-1] = TMath::Exp(dexp); continue;
4076  }
4077  case klog10: if (tab[pos-1] > 0) tab[pos-1] = TMath::Log10(tab[pos-1]);
4078  else {tab[pos-1] = 0;} //{indetermination }
4079  continue;
4080 
4081  case kpi : pos++; tab[pos-1] = TMath::ACos(-1); continue;
4082 
4083  case kabs : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
4084  case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1;
4085  continue;
4086  case kint : tab[pos-1] = T(Long64_t(tab[pos-1])); continue;
4087  case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
4088  case krndm : pos++; tab[pos-1] = gRandom->Rndm(); continue;
4089 
4090  case kAnd : pos--; if (tab[pos-1]!=0 && tab[pos]!=0) tab[pos-1]=1;
4091  else tab[pos-1]=0;
4092  continue;
4093  case kOr : pos--; if (tab[pos-1]!=0 || tab[pos]!=0) tab[pos-1]=1;
4094  else tab[pos-1]=0;
4095  continue;
4096 
4097  case kEqual : pos--; tab[pos-1] = (tab[pos-1] == tab[pos]) ? 1 : 0; continue;
4098  case kNotEqual : pos--; tab[pos-1] = (tab[pos-1] != tab[pos]) ? 1 : 0; continue;
4099  case kLess : pos--; tab[pos-1] = (tab[pos-1] < tab[pos]) ? 1 : 0; continue;
4100  case kGreater : pos--; tab[pos-1] = (tab[pos-1] > tab[pos]) ? 1 : 0; continue;
4101  case kLessThan : pos--; tab[pos-1] = (tab[pos-1] <= tab[pos]) ? 1 : 0; continue;
4102  case kGreaterThan: pos--; tab[pos-1] = (tab[pos-1] >= tab[pos]) ? 1 : 0; continue;
4103  case kNot : tab[pos-1] = (tab[pos-1] != 0) ? 0 : 1; continue;
4104 
4105  case kStringEqual : pos2 -= 2; pos++; if (!strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
4106  else tab[pos-1]=0;
4107  continue;
4108  case kStringNotEqual: pos2 -= 2; pos++;if (strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
4109  else tab[pos-1]=0;
4110  continue;
4111 
4112  case kBitAnd : pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) & ((ULong64_t) tab[pos]); continue;
4113  case kBitOr : pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) | ((ULong64_t) tab[pos]); continue;
4114  case kLeftShift : pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) <<((ULong64_t) tab[pos]); continue;
4115  case kRightShift: pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) >>((ULong64_t) tab[pos]); continue;
4116 
4117  case kJump : i = (oper & kTFOperMask); continue;
4118  case kJumpIf : {
4119  pos--;
4120  if (!tab[pos]) {
4121  i = (oper & kTFOperMask);
4122  // If we skip the left (true) side of the if statement we may,
4123  // skip some of the branch loading (since we remove duplicate branch
4124  // request (in TTreeFormula constructor) and so we need to force the
4125  // loading here.
4126  if (willLoad) fDidBooleanOptimization = kTRUE;
4127  }
4128  continue;
4129  }
4130 
4131  case kStringConst: {
4132  // String
4133  pos2++; stringStack[pos2-1] = (char*)fExpr[i].Data();
4134  if (fAxis) {
4135  // See TT_EVAL_INIT
4136  Int_t bin = fAxis->FindBin(stringStack[pos2-1]);
4137  return bin;
4138  }
4139  continue;
4140  }
4141 
4142  case kBoolOptimize: {
4143  // boolean operation optimizer
4144 
4145  int param = (oper & kTFOperMask);
4146  Bool_t skip = kFALSE;
4147  int op = param % 10; // 1 is && , 2 is ||
4148 
4149  if (op == 1 && (!tab[pos-1]) ) {
4150  // &&: skip the right part if the left part is already false
4151 
4152  skip = kTRUE;
4153 
4154  // Preserve the existing behavior (i.e. the result of a&&b is
4155  // either 0 or 1)
4156  tab[pos-1] = 0;
4157 
4158  } else if (op == 2 && tab[pos-1] ) {
4159  // ||: skip the right part if the left part is already true
4160 
4161  skip = kTRUE;
4162 
4163  // Preserve the existing behavior (i.e. the result of a||b is
4164  // either 0 or 1)
4165  tab[pos-1] = 1;
4166  }
4167 
4168  if (skip) {
4169  int toskip = param / 10;
4170  i += toskip;
4171  if (willLoad) fDidBooleanOptimization = kTRUE;
4172  }
4173  continue;
4174  }
4175 
4176  case kFunctionCall: {
4177  // an external function call
4178 
4179  int param = (oper & kTFOperMask);
4180  int fno = param / 1000;
4181  int nargs = param % 1000;
4182 
4183  // Retrieve the function
4184  TMethodCall *method = (TMethodCall*)fFunctions.At(fno);
4185 
4186  // Set the arguments
4187  method->ResetParam();
4188  if (nargs) {
4189  UInt_t argloc = pos-nargs;
4190  for(Int_t j=0;j<nargs;j++,argloc++,pos--) {
4191  SetMethodParam(method, tab[argloc]);
4192  }
4193  }
4194  pos++;
4195  Double_t ret = 0;
4196  method->Execute(ret);
4197  tab[pos-1] = ret; // check for the correct conversion!
4198 
4199  continue;
4200  }
4201 
4202 // case kParameter: { pos++; tab[pos-1] = fParams[(oper & kTFOperMask)]; continue; }
4203  }
4204 
4205  } else {
4206  // TTreeFormula operands.
4207 
4208  // a tree variable (the most used case).
4209 
4210  if (newaction == kDefinedVariable) {
4211 
4212  const Int_t code = (oper & kTFOperMask);
4213  const Int_t lookupType = fLookupType[code];
4214  switch (lookupType) {
4215  case kIndexOfEntry: tab[pos++] = (T)fTree->GetReadEntry(); continue;
4216  case kIndexOfLocalEntry: tab[pos++] = (T)fTree->GetTree()->GetReadEntry(); continue;
4217  case kEntries: tab[pos++] = (T)fTree->GetEntries(); continue;
4218  case kLocalEntries: tab[pos++] = (T)fTree->GetTree()->GetEntries(); continue;
4219  case kLength: tab[pos++] = fManager->fNdata; continue;
4220  case kLengthFunc: tab[pos++] = ((TTreeFormula*)fAliases.UncheckedAt(i))->GetNdata(); continue;
4221  case kIteration: tab[pos++] = instance; continue;
4222  case kSum: tab[pos++] = Summing<T>((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
4223  case kMin: tab[pos++] = FindMin<T>((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
4224  case kMax: tab[pos++] = FindMax<T>((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
4225 
4226  case kDirect: { TT_EVAL_INIT_LOOP; tab[pos++] = leaf->GetTypedValue<T>(real_instance); continue; }
4227  case kMethod: { TT_EVAL_INIT_LOOP; tab[pos++] = GetValueFromMethod(code,leaf); continue; }
4228  case kDataMember: { TT_EVAL_INIT_LOOP; tab[pos++] = ((TFormLeafInfo*)fDataMembers.UncheckedAt(code))->
4229  GetTypedValue<T>(leaf,real_instance); continue; }
4230  case kTreeMember: { TREE_EVAL_INIT_LOOP; tab[pos++] = ((TFormLeafInfo*)fDataMembers.UncheckedAt(code))->
4231  GetTypedValue<T>((TLeaf*)0x0,real_instance); continue; }
4232  case kEntryList: { TEntryList *elist = (TEntryList*)fExternalCuts.At(code);
4233  tab[pos++] = elist->Contains(fTree->GetReadEntry());
4234  continue;}
4235  case -1: break;
4236  default: tab[pos++] = 0; continue;
4237  }
4238  switch (fCodes[code]) {
4239  case -2: {
4240  TCutG *gcut = (TCutG*)fExternalCuts.At(code);
4241  TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
4242  TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
4243  T xcut = fx->EvalInstance<T>(instance);
4244  T ycut = fy->EvalInstance<T>(instance);
4245  tab[pos++] = gcut->IsInside(xcut,ycut);
4246  continue;
4247  }
4248  case -1: {
4249  TCutG *gcut = (TCutG*)fExternalCuts.At(code);
4250  TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
4251  tab[pos++] = fx->EvalInstance<T>(instance);
4252  continue;
4253  }
4254  default: {
4255  tab[pos++] = 0;
4256  continue;
4257  }
4258  }
4259  }
4260  switch(newaction) {
4261 
4262  // a TTree Variable Alias (i.e. a sub-TTreeFormula)
4263  case kAlias: {
4264  int aliasN = i;
4265  TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(aliasN));
4266  R__ASSERT(subform);
4267 
4269  T param = subform->EvalInstance<T>(instance);
4270 
4271  tab[pos] = param; pos++;
4272  continue;
4273  }
4274  // a TTree Variable Alias String (i.e. a sub-TTreeFormula)
4275  case kAliasString: {
4276  int aliasN = i;
4277  TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(aliasN));
4278  R__ASSERT(subform);
4279 
4280  pos2++;
4282  stringStack[pos2-1] = subform->EvalStringInstance(instance);
4283  continue;
4284  }
4285  case kMinIf: {
4286  int alternateN = i;
4287  TTreeFormula *primary = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN));
4288  TTreeFormula *condition = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN+1));
4289  T param = FindMin<T>(primary,condition);
4290  ++i; // skip the place holder for the condition
4291  tab[pos] = param; pos++;
4292  continue;
4293  }
4294  case kMaxIf: {
4295  int alternateN = i;
4296  TTreeFormula *primary = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN));
4297  TTreeFormula *condition = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN+1));
4298  T param = FindMax<T>(primary,condition);
4299  ++i; // skip the place holder for the condition
4300  tab[pos] = param; pos++;
4301  continue;
4302  }
4303 
4304  // a TTree Variable Alternate (i.e. a sub-TTreeFormula)
4305  case kAlternate: {
4306  int alternateN = i;
4307  TTreeFormula *primary = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN));
4308 
4309  // First check whether we are in range for the primary formula
4310  if (instance < primary->GetNdata()) {
4311 
4312  T param = primary->EvalInstance<T>(instance);
4313 
4314  ++i; // skip the alternate value.
4315 
4316  tab[pos] = param; pos++;
4317  } else {
4318  // The primary is not in rancge, we will calculate the alternate value
4319  // via the next operation (which will be a intentional).
4320 
4321  // kAlias no operations
4322  }
4323  continue;
4324  }
4325  case kAlternateString: {
4326  int alternateN = i;
4327  TTreeFormula *primary = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN));
4328 
4329  // First check whether we are in range for the primary formula
4330  if (instance < primary->GetNdata()) {
4331 
4332  pos2++;
4333  stringStack[pos2-1] = primary->EvalStringInstance(instance);
4334 
4335  ++i; // skip the alternate value.
4336 
4337  } else {
4338  // The primary is not in rancge, we will calculate the alternate value
4339  // via the next operation (which will be a kAlias).
4340 
4341  // intentional no operations
4342  }
4343  continue;
4344  }
4345 
4346  // a tree string
4347  case kDefinedString: {
4348  Int_t string_code = (oper & kTFOperMask);
4349  TLeaf *leafc = (TLeaf*)fLeaves.UncheckedAt(string_code);
4350 
4351  // Now let calculate what physical instance we really need.
4352  const Int_t real_instance = GetRealInstance(instance,string_code);
4353 
4354  if (instance==0 || fNeedLoading) {
4355  fNeedLoading = kFALSE;
4356  TBranch *branch = leafc->GetBranch();
4357  Long64_t readentry = branch->GetTree()->GetReadEntry();
4358  R__LoadBranch(branch,readentry,fQuickLoad);
4359  } else {
4360  // In the cases where we are behind (i.e. right of) a potential boolean optimization
4361  // this tree variable reading may have not been executed with instance==0 which would
4362  // result in the branch being potentially not read in.
4364  TBranch *br = leafc->GetBranch();
4365  Long64_t treeEntry = br->GetTree()->GetReadEntry();
4366  R__LoadBranch(br,treeEntry,kTRUE);
4367  }
4368  if (real_instance>=fNdata[string_code]) return 0;
4369  }
4370  pos2++;
4371  if (fLookupType[string_code]==kDirect) {
4372  stringStack[pos2-1] = (char*)leafc->GetValuePointer();
4373  } else {
4374  stringStack[pos2-1] = (char*)GetLeafInfo(string_code)->GetValuePointer(leafc,real_instance);
4375  }
4376  continue;
4377  }
4378 
4379  }
4380  }
4381 
4382  R__ASSERT(i<fNoper);
4383  }
4384 
4385  //std::cout << __PRETTY_FUNCTION__ << " returning " << tab[0] << std::endl;
4386  return tab[0];
4387 }
4388 
4389 // Template instantiations
4390 template double TTreeFormula::EvalInstance<double> (int, char const**);
4391 template long double TTreeFormula::EvalInstance<long double> (int, char const**);
4392 template long long TTreeFormula::EvalInstance<long long> (int, char const**);
4393 
4394 ////////////////////////////////////////////////////////////////////////////////
4395 /// Return DataMember corresponding to code.
4396 ///
4397 /// function called by TLeafObject::GetValue
4398 /// with the value of fLookupType computed in TTreeFormula::DefinedVariable
4399 
4401 {
4402  return (TFormLeafInfo *)fDataMembers.UncheckedAt(code);
4403 
4404 }
4405 
4406 ////////////////////////////////////////////////////////////////////////////////
4407 /// Return leaf corresponding to serial number n.
4408 
4410 {
4411  return (TLeaf*)fLeaves.UncheckedAt(n);
4412 }
4413 
4414 ////////////////////////////////////////////////////////////////////////////////
4415 /// Return methodcall corresponding to code.
4416 ///
4417 /// function called by TLeafObject::GetValue
4418 /// with the value of fLookupType computed in TTreeFormula::DefinedVariable
4419 
4421 {
4422  return (TMethodCall *)fMethods.UncheckedAt(code);
4423 
4424 }
4425 
4426 ////////////////////////////////////////////////////////////////////////////////
4427 /// Return number of available instances in the formula.
4428 
4430 {
4431  return fManager->GetNdata();
4432 }
4433 
4434 ////////////////////////////////////////////////////////////////////////////////
4435 /// Return result of a leafobject method.
4436 
4438 {
4439  TMethodCall* m = GetMethodCall(i);
4440 
4441  if (!m) {
4442  return 0.0;
4443  }
4444 
4445  void* thisobj = 0;
4446  if (leaf->InheritsFrom(TLeafObject::Class())) {
4447  thisobj = ((TLeafObject*) leaf)->GetObject();
4448  } else {
4449  TBranchElement* branch = (TBranchElement*) ((TLeafElement*) leaf)->GetBranch();
4450  Int_t id = branch->GetID();
4451  // FIXME: This is wrong for a top-level branch.
4452  Int_t offset = 0;
4453  if (id > -1) {
4454  TStreamerInfo* info = branch->GetInfo();
4455  if (info) {
4456  offset = info->GetElementOffset(id);
4457  } else {
4458  Warning("GetValueFromMethod", "No streamer info for branch %s.", branch->GetName());
4459  }
4460  }
4461  if (id < 0) {
4462  char* address = branch->GetObject();
4463  thisobj = address;
4464  } else {
4465  //char* address = branch->GetAddress();
4466  char* address = branch->GetObject();
4467  if (address) {
4468  thisobj = *((char**) (address + offset));
4469  } else {
4470  // FIXME: If the address is not set, the object won't be either!
4471  thisobj = branch->GetObject();
4472  }
4473  }
4474  }
4475 
4477 
4478  if (r == TMethodCall::kLong) {
4479  Long_t l = 0;
4480  m->Execute(thisobj, l);
4481  return (Double_t) l;
4482  }
4483 
4484  if (r == TMethodCall::kDouble) {
4485  Double_t d = 0.0;
4486  m->Execute(thisobj, d);
4487  return d;
4488  }
4489 
4490  m->Execute(thisobj);
4491 
4492  return 0;
4493 }
4494 
4495 ////////////////////////////////////////////////////////////////////////////////
4496 /// Return result of a leafobject method.
4497 
4499 {
4500  TMethodCall* m = GetMethodCall(i);
4501 
4502  if (!m) {
4503  return 0;
4504  }
4505 
4506  void* thisobj;
4507  if (leaf->InheritsFrom(TLeafObject::Class())) {
4508  thisobj = ((TLeafObject*) leaf)->GetObject();
4509  } else {
4510  TBranchElement* branch = (TBranchElement*) ((TLeafElement*) leaf)->GetBranch();
4511  Int_t id = branch->GetID();
4512  Int_t offset = 0;
4513  if (id > -1) {
4514  TStreamerInfo* info = branch->GetInfo();
4515  if (info) {
4516  offset = info->GetElementOffset(id);
4517  } else {
4518  Warning("GetValuePointerFromMethod", "No streamer info for branch %s.", branch->GetName());
4519  }
4520  }
4521  if (id < 0) {
4522  char* address = branch->GetObject();
4523  thisobj = address;
4524  } else {
4525  //char* address = branch->GetAddress();
4526  char* address = branch->GetObject();
4527  if (address) {
4528  thisobj = *((char**) (address + offset));
4529  } else {
4530  // FIXME: If the address is not set, the object won't be either!
4531  thisobj = branch->GetObject();
4532  }
4533  }
4534  }
4535 
4537 
4538  if (r == TMethodCall::kLong) {
4539  Long_t l = 0;
4540  m->Execute(thisobj, l);
4541  return 0;
4542  }
4543 
4544  if (r == TMethodCall::kDouble) {
4545  Double_t d = 0.0;
4546  m->Execute(thisobj, d);
4547  return 0;
4548  }
4549 
4550  if (r == TMethodCall::kOther) {
4551  char* c = 0;
4552  m->Execute(thisobj, &c);
4553  return c;
4554  }
4555 
4556  m->Execute(thisobj);
4557 
4558  return 0;
4559 }
4560 
4561 ////////////////////////////////////////////////////////////////////////////////
4562 /// Return TRUE if the formula corresponds to one single Tree leaf
4563 /// and this leaf is short, int or unsigned short, int
4564 /// When a leaf is of type integer or string, the generated histogram is forced
4565 /// to have an integer bin width
4566 
4568 {
4569  if (fast) {
4570  if (TestBit(kIsInteger)) return kTRUE;
4571  else return kFALSE;
4572  }
4573 
4574  if (fNoper==2 && GetAction(0)==kAlternate) {
4575  TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
4576  R__ASSERT(subform);
4577  return subform->IsInteger(kFALSE);
4578  }
4579 
4580  if (GetAction(0)==kMinIf || GetAction(0)==kMaxIf) {
4581  return kFALSE;
4582  }
4583 
4584  if (fNoper > 1) return kFALSE;
4585 
4586  if (GetAction(0)==kAlias) {
4587  TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
4588  R__ASSERT(subform);
4589  return subform->IsInteger(kFALSE);
4590  }
4591 
4592  if (fLeaves.GetEntries() != 1) {
4593  switch (fLookupType[0]) {
4594  case kIndexOfEntry:
4595  case kIndexOfLocalEntry:
4596  case kEntries:
4597  case kLocalEntries:
4598  case kLength:
4599  case kLengthFunc:
4600  case kIteration:
4601  return kTRUE;
4602  case kSum:
4603  case kMin:
4604  case kMax:
4605  case kEntryList:
4606  default:
4607  return kFALSE;
4608  }
4609  }
4610 
4611  if (EvalClass()==TBits::Class()) return kTRUE;
4612 
4613  if (IsLeafInteger(0) || IsLeafString(0)) return kTRUE;
4614  return kFALSE;
4615 }
4616 
4617 ////////////////////////////////////////////////////////////////////////////////
4618 /// Return TRUE if the leaf corresponding to code is short, int or unsigned
4619 /// short, int When a leaf is of type integer, the generated histogram is
4620 /// forced to have an integer bin width
4621 
4623 {
4624  TLeaf *leaf = (TLeaf*)fLeaves.At(code);
4625  if (!leaf) {
4626  switch (fLookupType[code]) {
4627  case kIndexOfEntry:
4628  case kIndexOfLocalEntry:
4629  case kEntries:
4630  case kLocalEntries:
4631  case kLength:
4632  case kLengthFunc:
4633  case kIteration:
4634  return kTRUE;
4635  case kSum:
4636  case kMin:
4637  case kMax:
4638  case kEntryList:
4639  default:
4640  return kFALSE;
4641  }
4642  }
4643  if (fAxis) return kTRUE;
4644  TFormLeafInfo * info;
4645  switch (fLookupType[code]) {
4646  case kMethod:
4647  case kTreeMember:
4648  case kDataMember:
4649  info = GetLeafInfo(code);
4650  return info->IsInteger();
4651  case kDirect:
4652  break;
4653  }
4654  if (!strcmp(leaf->GetTypeName(),"Int_t")) return kTRUE;
4655  if (!strcmp(leaf->GetTypeName(),"Short_t")) return kTRUE;
4656  if (!strcmp(leaf->GetTypeName(),"UInt_t")) return kTRUE;
4657  if (!strcmp(leaf->GetTypeName(),"UShort_t")) return kTRUE;
4658  if (!strcmp(leaf->GetTypeName(),"Bool_t")) return kTRUE;
4659  if (!strcmp(leaf->GetTypeName(),"Char_t")) return kTRUE;
4660  if (!strcmp(leaf->GetTypeName(),"UChar_t")) return kTRUE;
4661  if (!strcmp(leaf->GetTypeName(),"Long64_t")) return kTRUE;
4662  if (!strcmp(leaf->GetTypeName(),"ULong64_t")) return kTRUE;
4663  if (!strcmp(leaf->GetTypeName(),"string")) return kTRUE;
4664  return kFALSE;
4665 }
4666 
4667 ////////////////////////////////////////////////////////////////////////////////
4668 /// Return TRUE if the formula is a string
4669 
4671 {
4672  // See TTreeFormula::Init for the setting of kIsCharacter.
4673  return TestBit(kIsCharacter);
4674 }
4675 
4676 ////////////////////////////////////////////////////////////////////////////////
4677 /// Return true if the expression at the index 'oper' is to be treated as
4678 /// as string.
4679 
4681 {
4682  if (ROOT::v5::TFormula::IsString(oper)) return kTRUE;
4683  if (GetAction(oper)==kDefinedString) return kTRUE;
4684  if (GetAction(oper)==kAliasString) return kTRUE;
4685  if (GetAction(oper)==kAlternateString) return kTRUE;
4686  return kFALSE;
4687 }
4688 
4689 ////////////////////////////////////////////////////////////////////////////////
4690 /// Return TRUE if the leaf or data member corresponding to code is a string
4691 
4693 {
4694  TLeaf *leaf = (TLeaf*)fLeaves.At(code);
4695  TFormLeafInfo * info;
4696  if (fLookupType[code]==kTreeMember) {
4697  info = GetLeafInfo(code);
4698  return info->IsString();
4699  }
4700 
4701  switch(fLookupType[code]) {
4702  case kDirect:
4703  if ( !leaf->IsUnsigned() && (leaf->InheritsFrom(TLeafC::Class()) || leaf->InheritsFrom(TLeafB::Class()) ) ) {
4704  // Need to find out if it is an 'array' or a pointer.
4705  if (leaf->GetLenStatic() > 1) return kTRUE;
4706 
4707  // Now we need to differantiate between a variable length array and
4708  // a TClonesArray.
4709  if (leaf->GetLeafCount()) {
4710  const char* indexname = leaf->GetLeafCount()->GetName();
4711  if (indexname[strlen(indexname)-1] == '_' ) {
4712  // This in a clones array
4713  return kFALSE;
4714  } else {
4715  // this is a variable length char array
4716  return kTRUE;
4717  }
4718  }
4719  return kFALSE;
4720  } else if (leaf->InheritsFrom(TLeafElement::Class())) {
4721  TBranchElement * br = (TBranchElement*)leaf->GetBranch();
4722  Int_t bid = br->GetID();
4723  if (bid < 0) return kFALSE;
4724  if (br->GetInfo()==0 || !br->GetInfo()->IsCompiled()) {
4725  // Case where the file is corrupted is some ways.
4726  // We can not get to the actual type of the data
4727  // let's assume it is NOT a string.
4728  return kFALSE;
4729  }
4730  TStreamerElement * elem = (TStreamerElement*) br->GetInfo()->GetElement(bid);
4731  if (!elem) {
4732  // Case where the file is corrupted is some ways.
4733  // We can not get to the actual type of the data
4734  // let's assume it is NOT a string.
4735  return kFALSE;
4736  }
4737  if (elem->GetNewType()== TStreamerInfo::kOffsetL +kChar_t) {
4738  // Check whether a specific element of the string is specified!
4739  if (fIndexes[code][fNdimensions[code]-1] != -1) return kFALSE;
4740  return kTRUE;
4741  }
4742  if ( elem->GetNewType()== TStreamerInfo::kCharStar) {
4743  // Check whether a specific element of the string is specified!
4744  if (fNdimensions[code] && fIndexes[code][fNdimensions[code]-1] != -1) return kFALSE;
4745  return kTRUE;
4746  }
4747  return kFALSE;
4748  } else {
4749  return kFALSE;
4750  }
4751  case kMethod:
4752  //TMethodCall *m = GetMethodCall(code);
4753  //TMethodCall::EReturnType r = m->ReturnType();
4754  return kFALSE;
4755  case kDataMember:
4756  info = GetLeafInfo(code);
4757  return info->IsString();
4758  default:
4759  return kFALSE;
4760  }
4761 }
4762 
4763 ////////////////////////////////////////////////////////////////////////////////
4764 /// Return value of variable as a string
4765 ///
4766 /// - mode = -2 : Print line with ***
4767 /// - mode = -1 : Print column names
4768 /// - mode = 0 : Print column values
4769 
4771 {
4772  return PrintValue(mode,0);
4773 }
4774 
4775 ////////////////////////////////////////////////////////////////////////////////
4776 /// Return value of variable as a string
4777 ///
4778 /// - mode = -2 : Print line with ***
4779 /// - mode = -1 : Print column names
4780 /// - mode = 0 : Print column values
4781 ///
4782 /// decform contains the requested format (with the same convention as printf).
4783 
4784 char *TTreeFormula::PrintValue(Int_t mode, Int_t instance, const char *decform) const
4785 {
4786  const int kMAXLENGTH = 1024;
4787  static char value[kMAXLENGTH];
4788 
4789  if (mode == -2) {
4790  for (int i = 0; i < kMAXLENGTH-1; i++)
4791  value[i] = '*';
4792  value[kMAXLENGTH-1] = 0;
4793  } else if (mode == -1) {
4794  snprintf(value, kMAXLENGTH-1, "%s", GetTitle());
4795  } else if (mode == 0) {
4796  if ( (fNstring && fNval==0 && fNoper==1) || IsString() )
4797  {
4798  const char * val = 0;
4799  if (GetAction(0)==kStringConst) {
4800  val = fExpr[0].Data();
4801  } else if (instance<fNdata[0]) {
4802  if (fNoper == 1) {
4803  if (fLookupType[0]==kTreeMember) {
4804  val = (char*)GetLeafInfo(0)->GetValuePointer((TLeaf*)0x0,instance);
4805  } else {
4806  TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);
4807  TBranch *branch = leaf->GetBranch();
4808  Long64_t readentry = branch->GetTree()->GetReadEntry();
4809  R__LoadBranch(branch,readentry,fQuickLoad);
4810  if (fLookupType[0]==kDirect && fNoper==1) {
4811  val = (const char*)leaf->GetValuePointer();
4812  } else {
4813  val = ((TTreeFormula*)this)->EvalStringInstance(instance);
4814  }
4815  }
4816  } else {
4817  val = ((TTreeFormula*)this)->EvalStringInstance(instance);
4818  }
4819  }
4820  if (val) {
4821  strlcpy(value, val, kMAXLENGTH);
4822  } else {
4823  value[0] = '\0';
4824  }
4825  value[kMAXLENGTH-1] = 0;
4826  } else {
4827  //NOTE: This is terrible form ... but is forced upon us by the fact that we can not
4828  //use the mutable keyword AND we should keep PrintValue const.
4829  Int_t real_instance = ((TTreeFormula*)this)->GetRealInstance(instance,-1);
4830  if (real_instance<fNdata[0]) {
4831  Ssiz_t len = strlen(decform);
4832  Char_t outputSizeLevel = 1;
4833  char *expo = 0;
4834  if (len>2) {
4835  switch (decform[len-2]) {
4836  case 'l':
4837  case 'L': {
4838  outputSizeLevel = 2;
4839  if (len>3 && tolower(decform[len-3])=='l') {
4840  outputSizeLevel = 3;
4841  }
4842  break;
4843  }
4844  case 'h': outputSizeLevel = 0; break;
4845  }
4846  }
4847  switch(decform[len-1]) {
4848  case 'c':
4849  case 'd':
4850  case 'i':
4851  {
4852  switch (outputSizeLevel) {
4853  case 0: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Short_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4854  case 2: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Long_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4855  case 3: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Long64_t)((TTreeFormula*)this)->EvalInstance<LongDouble_t>(instance)); break;
4856  case 1:
4857  default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Int_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4858  }
4859  break;
4860  }
4861  case 'o':
4862  case 'x':
4863  case 'X':
4864  case 'u':
4865  {
4866  switch (outputSizeLevel) {
4867  case 0: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(UShort_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4868  case 2: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(ULong_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4869  case 3: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(ULong64_t)((TTreeFormula*)this)->EvalInstance<LongDouble_t>(instance)); break;
4870  case 1:
4871  default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(UInt_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4872  }
4873  break;
4874  }
4875  case 'f':
4876  case 'e':
4877  case 'E':
4878  case 'g':
4879  case 'G':
4880  {
4881  switch (outputSizeLevel) {
4882  case 2: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(LongDouble_t)((TTreeFormula*)this)->EvalInstance<LongDouble_t>(instance)); break;
4883  case 1:
4884  default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),((TTreeFormula*)this)->EvalInstance(instance)); break;
4885  }
4886  expo = strchr(value,'e');
4887  break;
4888  }
4889  default:
4890  snprintf(value,kMAXLENGTH,Form("%%%sg",decform),((TTreeFormula*)this)->EvalInstance(instance));
4891  expo = strchr(value,'e');
4892  }
4893  if (expo) {
4894  // If there is an exponent we may be longer than planned.
4895  // so let's trim off the excess precission!
4896  UInt_t declen = atoi(decform);
4897  if (strlen(value)>declen) {
4898  UInt_t off = strlen(value)-declen;
4899  char *start = expo - off;
4900  UInt_t vlen = strlen(expo);
4901  for(UInt_t z=0;z<=vlen;++z) {
4902  start[z] = expo[z];
4903  }
4904  //strcpy(expo-off,expo);
4905  }
4906  }
4907  } else {
4908  if (isalpha(decform[strlen(decform)-1])) {
4909  TString short_decform(decform);
4910  short_decform.Remove(short_decform.Length()-1);
4911  snprintf(value,kMAXLENGTH,Form(" %%%sc",short_decform.Data()),' ');
4912  } else {
4913  snprintf(value,kMAXLENGTH,Form(" %%%sc",decform),' ');
4914  }
4915 
4916  }
4917  }
4918  }
4919  return &value[0];
4920 }
4921 
4922 ////////////////////////////////////////////////////////////////////////////////
4923 /// Tell the formula that we are going to request a new entry.
4924 
4926 {
4927  fNeedLoading = kTRUE;
4929 
4930  for(Int_t i=0; i<fNcodes; ++i) {
4931  UInt_t max_dim = fNdimensions[i];
4932  for(UInt_t dim=0; dim<max_dim ;++dim) {
4933  if (fVarIndexes[i][dim]) {
4934  fVarIndexes[i][dim]->ResetLoading();
4935  }
4936  }
4937  }
4938  Int_t n = fAliases.GetLast();
4939  if ( fNoper < n ) {
4940  n = fNoper;
4941  }
4942  for(Int_t k=0; k <= n; ++k) {
4943  TTreeFormula *f = static_cast<TTreeFormula*>(fAliases.UncheckedAt(k));
4944  if (f) {
4945  f->ResetLoading();
4946  }
4947  }
4948 }
4949 
4950 ////////////////////////////////////////////////////////////////////////////////
4951 /// Set the axis (in particular get the type).
4952 
4954 {
4955  if (!axis) {fAxis = 0; return;}
4956  if (IsString()) {
4957  fAxis = axis;
4958  if (fNoper==1 && GetAction(0)==kAliasString){
4959  TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
4960  R__ASSERT(subform);
4961  subform->SetAxis(axis);
4962  } else if (fNoper==2 && GetAction(0)==kAlternateString){
4963  TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
4964  R__ASSERT(subform);
4965  subform->SetAxis(axis);
4966  }
4967  // Since the bin are corresponding to 'string', we currently must also set
4968  // the axis to align the bins exactly on integer boundaries.
4969  axis->SetBit(TAxis::kIsInteger);
4970  } else if (IsInteger()) {
4971  axis->SetBit(TAxis::kIsInteger);
4972  }
4973 }
4974 
4975 ////////////////////////////////////////////////////////////////////////////////
4976 /// Stream an object of class TTreeFormula.
4977 
4978 void TTreeFormula::Streamer(TBuffer &R__b)
4979 {
4980  if (R__b.IsReading()) {
4981  UInt_t R__s, R__c;
4982  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
4983  if (R__v > 2) {
4984  R__b.ReadClassBuffer(TTreeFormula::Class(), this, R__v, R__s, R__c);
4985  return;
4986  }
4987  //====process old versions before automatic schema evolution
4989  R__b >> fTree;
4990  R__b >> fNcodes;
4991  R__b.ReadFastArray(fCodes, fNcodes);
4992  R__b >> fMultiplicity;
4993  Int_t instance;
4994  R__b >> instance; //data member removed
4995  R__b >> fNindex;
4996  if (fNindex) {
4997  fLookupType = new Int_t[fNindex];
4998  R__b.ReadFastArray(fLookupType, fNindex);
4999  }
5000  fMethods.Streamer(R__b);
5001  //====end of old versions
5002 
5003  } else {
5005  }
5006 }
5007 
5008 ////////////////////////////////////////////////////////////////////////////////
5009 /// Try to 'demote' a string into an array bytes. If this is not possible,
5010 /// return false.
5011 
5013 {
5014  Int_t code = GetActionParam(oper);
5015  if (GetAction(oper)==kDefinedString && fLookupType[code]==kDirect) {
5016  if (oper>0 && GetAction(oper-1)==kJump) {
5017  // We are the second hand of a ternary operator, let's not do the fixing.
5018  return kFALSE;
5019  }
5020  TLeaf *leaf = (TLeaf*)fLeaves.At(code);
5021  if (leaf && (leaf->InheritsFrom(TLeafC::Class()) || leaf->InheritsFrom(TLeafB::Class()) ) ) {
5022  SetAction(oper, kDefinedVariable, code );
5023  fNval++;
5024  fNstring--;
5025  return kTRUE;
5026  }
5027  }
5028  return kFALSE;
5029 }
5030 
5031 
5032 ////////////////////////////////////////////////////////////////////////////////
5033 /// This function is called TTreePlayer::UpdateFormulaLeaves, itself
5034 /// called by TChain::LoadTree when a new Tree is loaded.
5035 /// Because Trees in a TChain may have a different list of leaves, one
5036 /// must update the leaves numbers in the TTreeFormula used by the TreePlayer.
5037 ///
5038 /// A safer alternative would be to recompile the whole thing .... However
5039 /// currently compile HAS TO be called from the constructor!
5040 
5042 {
5043  Int_t nleaves = fLeafNames.GetEntriesFast();
5045  for (Int_t i=0;i<nleaves;i++) {
5046  if (!fTree) break;
5047  if (!fLeafNames[i]) continue;
5048 
5049  TLeaf *leaf = fTree->GetLeaf(fLeafNames[i]->GetTitle(),fLeafNames[i]->GetName());
5050  fLeaves[i] = leaf;
5051  if (fBranches[i] && leaf) {
5052  fBranches[i] = leaf->GetBranch();
5053  // Since sometimes we might no read all the branches for all the entries, we
5054  // might sometimes only read the branch count and thus reset the colleciton
5055  // but might not read the data branches, to insure that a subsequent read
5056  // from TTreeFormula will properly load the data branches even if fQuickLoad is true,
5057  // we reset the entry of all branches in the TTree.
5058  ((TBranch*)fBranches[i])->ResetReadEntry();
5059  }
5060  if (leaf==0) SetBit( kMissingLeaf );
5061  }
5062  for (Int_t j=0; j<kMAXCODES; j++) {
5063  for (Int_t k = 0; k<kMAXFORMDIM; k++) {
5064  if (fVarIndexes[j][k]) {
5066  }
5067  }
5069  if (j<fNval && fCodes[j]<0) {
5070  TCutG *gcut = (TCutG*)fExternalCuts.At(j);
5071  if (gcut) {
5072  TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
5073  TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
5074  if (fx) fx->UpdateFormulaLeaves();
5075  if (fy) fy->UpdateFormulaLeaves();
5076  }
5077  }
5078  }
5079  for(Int_t k=0;k<fNoper;k++) {
5080  const Int_t oper = GetOper()[k];
5081  switch(oper >> kTFOperShift) {
5082  case kAlias:
5083  case kAliasString:
5084  case kAlternate:
5085  case kAlternateString:
5086  case kMinIf:
5087  case kMaxIf:
5088  {
5089  TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(k));
5090  R__ASSERT(subform);
5091  subform->UpdateFormulaLeaves();
5092  break;
5093  }
5094  case kDefinedVariable:
5095  {
5096  Int_t code = GetActionParam(k);
5097  if (fCodes[code]==0) switch(fLookupType[code]) {
5098  case kLengthFunc:
5099  case kSum:
5100  case kMin:
5101  case kMax:
5102  {
5103  TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(k));
5104  R__ASSERT(subform);
5105  subform->UpdateFormulaLeaves();
5106  break;
5107  }
5108  default:
5109  break;
5110  }
5111  }
5112  default:
5113  break;
5114  }
5115  }
5116 }
5117 
5118 ////////////////////////////////////////////////////////////////////////////////
5119 /// Populate the TTreeFormulaManager with the dimension information.
5120 
5122  Int_t i,k;
5123 
5124  // Now that we saw all the expressions and variables AND that
5125  // we know whether arrays of chars are treated as string or
5126  // not, we can properly setup the dimensions.
5127  TIter next(fDimensionSetup);
5128  Int_t last_code = -1;
5129  Int_t virt_dim = 0;
5130  for(TDimensionInfo * info; (info = (TDimensionInfo*)next()); ) {
5131  if (last_code!=info->fCode) {
5132  // We know that the list is ordered by code number then by
5133  // dimension. Thus a different code means that we need to
5134  // restart at the lowest dimensions.
5135  virt_dim = 0;
5136  last_code = info->fCode;
5137  fNdimensions[last_code] = 0;