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