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