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