TTreeFormula.cxx

Go to the documentation of this file.
00001 // @(#)root/treeplayer:$Id: TTreeFormula.cxx 36672 2010-11-15 17:27:36Z pcanal $
00002 // Author: Rene Brun   19/01/96
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "TROOT.h"
00013 #include "TTreeFormula.h"
00014 #include "TTree.h"
00015 #include "TBranch.h"
00016 #include "TBranchObject.h"
00017 #include "TFunction.h"
00018 #include "TClonesArray.h"
00019 #include "TLeafB.h"
00020 #include "TLeafC.h"
00021 #include "TLeafObject.h"
00022 #include "TDataMember.h"
00023 #include "TMethodCall.h"
00024 #include "TCutG.h"
00025 #include "TRandom.h"
00026 #include "TInterpreter.h"
00027 #include "TDataType.h"
00028 #include "TStreamerInfo.h"
00029 #include "TStreamerElement.h"
00030 #include "TBranchElement.h"
00031 #include "TLeafElement.h"
00032 #include "TArrayI.h"
00033 #include "TAxis.h"
00034 #include "TError.h"
00035 #include "TVirtualCollectionProxy.h"
00036 #include "TString.h"
00037 #include "TTimeStamp.h"
00038 #include "TMath.h"
00039 
00040 #include "TVirtualRefProxy.h"
00041 #include "TTreeFormulaManager.h"
00042 #include "TFormLeafInfo.h"
00043 #include "TMethod.h"
00044 #include "TBaseClass.h"
00045 #include "TFormLeafInfoReference.h"
00046 
00047 #include "TEntryList.h"
00048 
00049 #include <ctype.h>
00050 #include <stdio.h>
00051 #include <math.h>
00052 #include <stdlib.h>
00053 #include <typeinfo>
00054 #include <algorithm>
00055 
00056 const Int_t kMaxLen     = 1024;
00057 R__EXTERN TTree *gTree;
00058 
00059 
00060 
00061 ClassImp(TTreeFormula)
00062 
00063 //______________________________________________________________________________
00064 //
00065 // TTreeFormula now relies on a variety of TFormLeafInfo classes to handle the
00066 // reading of the information.  Here is the list of theses classes:
00067 //   TFormLeafInfo
00068 //   TFormLeafInfoDirect
00069 //   TFormLeafInfoNumerical
00070 //   TFormLeafInfoClones
00071 //   TFormLeafInfoCollection
00072 //   TFormLeafInfoPointer
00073 //   TFormLeafInfoMethod
00074 //   TFormLeafInfoMultiVarDim
00075 //   TFormLeafInfoMultiVarDimDirect
00076 //   TFormLeafInfoCast
00077 //
00078 // The following method are available from the TFormLeafInfo interface:
00079 //
00080 //  AddOffset(Int_t offset, TStreamerElement* element)
00081 //  GetCounterValue(TLeaf* leaf) : return the size of the array pointed to.
00082 //  GetObjectAddress(TLeafElement* leaf) : Returns the the location of the object pointed to.
00083 //  GetMultiplicity() : Returns info on the variability of the number of elements
00084 //  GetNdata(TLeaf* leaf) : Returns the number of elements
00085 //  GetNdata() : Used by GetNdata(TLeaf* leaf)
00086 //  GetValue(TLeaf *leaf, Int_t instance = 0) : Return the value
00087 //  GetValuePointer(TLeaf *leaf, Int_t instance = 0) : Returns the address of the value
00088 //  GetLocalValuePointer(TLeaf *leaf, Int_t instance = 0) : Returns the address of the value of 'this' LeafInfo
00089 //  IsString()
00090 //  ReadValue(char *where, Int_t instance = 0) : Internal function to interpret the location 'where'
00091 //  Update() : react to the possible loading of a shared library.
00092 //
00093 //
00094 
00095 //______________________________________________________________________________
00096 inline static void R__LoadBranch(TBranch* br, Long64_t entry, Bool_t quickLoad)
00097 {
00098    if (!quickLoad || (br->GetReadEntry() != entry)) {
00099       br->GetEntry(entry);
00100    }
00101 }
00102 
00103 //______________________________________________________________________________
00104 //
00105 // This class is a small helper class to help in keeping track of the array
00106 // dimensions encountered in the analysis of the expression.
00107 class TDimensionInfo : public TObject {
00108 public:
00109    Int_t fCode;  // Location of the leaf in TTreeFormula::fCode
00110    Int_t fOper;  // Location of the Operation using the leaf in TTreeFormula::fOper
00111    Int_t fSize;
00112    TFormLeafInfoMultiVarDim* fMultiDim;
00113    TDimensionInfo(Int_t code, Int_t oper, Int_t size, TFormLeafInfoMultiVarDim* multiDim)
00114       : fCode(code), fOper(oper), fSize(size), fMultiDim(multiDim) {};
00115    ~TDimensionInfo() {};
00116 };
00117 
00118 //______________________________________________________________________________
00119 //
00120 //     A TreeFormula is used to pass a selection expression
00121 //     to the Tree drawing routine. See TTree::Draw
00122 //
00123 //  A TreeFormula can contain any arithmetic expression including
00124 //  standard operators and mathematical functions separated by operators.
00125 //  Examples of valid expression:
00126 //          "x<y && sqrt(z)>3.2"
00127 //
00128 
00129 //______________________________________________________________________________
00130 TTreeFormula::TTreeFormula(): TFormula(), fQuickLoad(kFALSE), fNeedLoading(kTRUE),
00131    fDidBooleanOptimization(kFALSE), fDimensionSetup(0)
00132 
00133 {
00134    // Tree Formula default constructor
00135 
00136    fTree         = 0;
00137    fLookupType   = 0;
00138    fNindex       = 0;
00139    fNcodes       = 0;
00140    fAxis         = 0;
00141    fHasCast      = 0;
00142    fManager      = 0;
00143    fMultiplicity = 0;
00144 
00145    Int_t j,k;
00146    for (j=0; j<kMAXCODES; j++) {
00147       fNdimensions[j] = 0;
00148       fCodes[j] = 0;
00149       fNdata[j] = 1;
00150       fHasMultipleVarDim[j] = kFALSE;
00151       for (k = 0; k<kMAXFORMDIM; k++) {
00152          fIndexes[j][k] = -1;
00153          fCumulSizes[j][k] = 1;
00154          fVarIndexes[j][k] = 0;
00155       }
00156    }
00157 }
00158 
00159 //______________________________________________________________________________
00160 TTreeFormula::TTreeFormula(const char *name,const char *expression, TTree *tree)
00161    :TFormula(), fTree(tree), fQuickLoad(kFALSE), fNeedLoading(kTRUE),
00162     fDidBooleanOptimization(kFALSE), fDimensionSetup(0)
00163 {
00164    // Normal TTree Formula Constuctor
00165 
00166    Init(name,expression);
00167 }
00168 
00169 //______________________________________________________________________________
00170 TTreeFormula::TTreeFormula(const char *name,const char *expression, TTree *tree,
00171                            const std::vector<std::string>& aliases)
00172    :TFormula(), fTree(tree), fQuickLoad(kFALSE), fNeedLoading(kTRUE),
00173     fDidBooleanOptimization(kFALSE), fDimensionSetup(0), fAliasesUsed(aliases)
00174 {
00175    // Constructor used during the expansion of an alias
00176    Init(name,expression);
00177 }
00178 
00179 //______________________________________________________________________________
00180 void TTreeFormula::Init(const char*name, const char* expression)
00181 {
00182    // Initialiation called from the constructors.
00183 
00184    TDirectory *const savedir=gDirectory;
00185 
00186    fNindex       = kMAXFOUND;
00187    fLookupType   = new Int_t[fNindex];
00188    fNcodes       = 0;
00189    fMultiplicity = 0;
00190    fAxis         = 0;
00191    fHasCast      = 0;
00192    Int_t i,j,k;
00193    fManager      = new TTreeFormulaManager;
00194    fManager->Add(this);
00195 
00196    for (j=0; j<kMAXCODES; j++) {
00197       fNdimensions[j] = 0;
00198       fLookupType[j] = kDirect;
00199       fCodes[j] = 0;
00200       fNdata[j] = 1;
00201       fHasMultipleVarDim[j] = kFALSE;
00202       for (k = 0; k<kMAXFORMDIM; k++) {
00203          fIndexes[j][k] = -1;
00204          fCumulSizes[j][k] = 1;
00205          fVarIndexes[j][k] = 0;
00206       }
00207    }
00208 
00209    fDimensionSetup = new TList;
00210 
00211    if (Compile(expression)) {
00212       fTree = 0; fNdim = 0; 
00213       if(savedir) savedir->cd();
00214       return; 
00215    }
00216 
00217    if (fNcodes >= kMAXFOUND) {
00218       Warning("TTreeFormula","Too many items in expression:%s",expression);
00219       fNcodes = kMAXFOUND;
00220    }
00221    SetName(name);
00222 
00223    for (i=0;i<fNoper;i++) {
00224 
00225       if (GetAction(i)==kDefinedString) {
00226          Int_t string_code = GetActionParam(i);
00227          TLeaf *leafc = (TLeaf*)fLeaves.UncheckedAt(string_code);
00228          if (!leafc) continue;
00229 
00230          // We have a string used as a string
00231 
00232          // This dormant portion of code would be used if (when?) we allow the histogramming
00233          // of the integral content (as opposed to the string content) of strings
00234          // held in a variable size container delimited by a null (as opposed to
00235          // a fixed size container or variable size container whose size is controlled
00236          // by a variable).  In GetNdata, we will then use strlen to grab the current length.
00237          //fCumulSizes[i][fNdimensions[i]-1] = 1;
00238          //fUsedSizes[fNdimensions[i]-1] = -TMath::Abs(fUsedSizes[fNdimensions[i]-1]);
00239          //fUsedSizes[0] = - TMath::Abs( fUsedSizes[0]);
00240 
00241          if (fNcodes == 1) {
00242             // If the string is by itself, then it can safely be histogrammed as
00243             // in a string based axis.  To histogram the number inside the string
00244             // just make it part of a useless expression (for example: mystring+0)
00245             SetBit(kIsCharacter);
00246          }
00247          continue;
00248       }
00249       if (GetAction(i)==kJump && GetActionParam(i)==(fNoper-1)) {
00250          // We have cond ? string1 : string2
00251          if (IsString(fNoper-1)) SetBit(kIsCharacter);
00252       }
00253    }
00254    if (fNoper==1 && GetAction(0)==kAliasString) {
00255       TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
00256       R__ASSERT(subform);
00257       if (subform->TestBit(kIsCharacter)) SetBit(kIsCharacter);
00258    } else if (fNoper==2 && GetAction(0)==kAlternateString) {
00259       TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
00260       R__ASSERT(subform);
00261       if (subform->TestBit(kIsCharacter)) SetBit(kIsCharacter);
00262    }
00263 
00264    fManager->Sync();
00265 
00266    // Let's verify the indexes and dies if we need to.
00267    Int_t k0,k1;
00268    for(k0 = 0; k0 < fNcodes; k0++) {
00269       for(k1 = 0; k1 < fNdimensions[k0]; k1++ ) {
00270          // fprintf(stderr,"Saw %d dim %d and index %d\n",k1, fFixedSizes[k0][k1], fIndexes[k0][k1]);
00271          if ( fIndexes[k0][k1]>=0 && fFixedSizes[k0][k1]>=0
00272               && fIndexes[k0][k1]>=fFixedSizes[k0][k1]) {
00273             Error("TTreeFormula",
00274                   "Index %d for dimension #%d in %s is too high (max is %d)",
00275                   fIndexes[k0][k1],k1+1, expression,fFixedSizes[k0][k1]-1);
00276             fTree = 0; fNdim = 0; 
00277             if(savedir) savedir->cd();
00278             return;
00279          }
00280       }
00281    }
00282 
00283    // Create a list of uniques branches to load.
00284    for(k=0; k<fNcodes; k++) {
00285       TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(k);
00286       TBranch *branch = 0;
00287       if (leaf) {
00288          branch = leaf->GetBranch();
00289          if (fBranches.FindObject(branch)) branch = 0;
00290       }
00291       fBranches.AddAtAndExpand(branch,k);
00292    }
00293    
00294    if (IsInteger(kFALSE)) SetBit(kIsInteger);
00295 
00296    if (TestBit(TTreeFormula::kNeedEntries)) { 
00297       // Call TTree::GetEntries() to insure that it is already calculated.
00298       // This will need to be done anyway at the first iteration and insure
00299       // that it will not mess up the branch reading (because TTree::GetEntries
00300       // opens all the file in the chain and 'stays' on the last file.
00301       
00302       Long64_t readentry = fTree->GetReadEntry();
00303       Int_t treenumber = fTree->GetTreeNumber();
00304       fTree->GetEntries();
00305       if (treenumber != fTree->GetTreeNumber()) {
00306          if (readentry != -1) {
00307             fTree->LoadTree(readentry);
00308          }
00309          UpdateFormulaLeaves();
00310       } else {
00311          if (readentry != -1) {
00312             fTree->LoadTree(readentry);
00313          }
00314       }
00315 
00316    }
00317 
00318    if(savedir) savedir->cd();
00319 }
00320 
00321 //______________________________________________________________________________
00322 TTreeFormula::~TTreeFormula()
00323 {
00324 //*-*-*-*-*-*-*-*-*-*-*Tree Formula default destructor*-*-*-*-*-*-*-*-*-*-*
00325 //*-*                  =================================
00326    if (fManager) {
00327       fManager->Remove(this);
00328       if (fManager->fFormulas.GetLast()<0) {
00329          delete fManager;
00330          fManager = 0;
00331       }
00332    }
00333    // Objects in fExternalCuts are not owned and should not be deleted
00334    // fExternalCuts.Clear();
00335    fLeafNames.Delete();
00336    fDataMembers.Delete();
00337    fMethods.Delete();
00338    fAliases.Delete();
00339    if (fLookupType) delete [] fLookupType;
00340    for (int j=0; j<fNcodes; j++) {
00341       for (int k = 0; k<fNdimensions[j]; k++) {
00342          if (fVarIndexes[j][k]) delete fVarIndexes[j][k];
00343          fVarIndexes[j][k] = 0;
00344       }
00345    }
00346    if (fDimensionSetup) {
00347       fDimensionSetup->Delete();
00348       delete fDimensionSetup;
00349    }
00350 }
00351 
00352 //______________________________________________________________________________
00353 void TTreeFormula::DefineDimensions(Int_t code, Int_t size,
00354                                     TFormLeafInfoMultiVarDim * info,
00355                                     Int_t& virt_dim) {
00356    // This method is used internally to decode the dimensions of the variables
00357 
00358    if (info) {
00359       fManager->EnableMultiVarDims();
00360       //if (fIndexes[code][info->fDim]<0) { // removed because the index might be out of bounds!
00361          info->fVirtDim = virt_dim;
00362          fManager->AddVarDims(virt_dim); // if (!fVarDims[virt_dim]) fVarDims[virt_dim] = new TArrayI;
00363       //}
00364    }
00365 
00366    Int_t vsize = 0;
00367 
00368    if (fIndexes[code][fNdimensions[code]]==-2) {
00369       TTreeFormula *indexvar = fVarIndexes[code][fNdimensions[code]];
00370       // ASSERT(indexvar!=0);
00371       Int_t index_multiplicity = indexvar->GetMultiplicity();
00372       switch (index_multiplicity) {
00373          case -1:
00374          case  0:
00375          case  2:
00376             vsize = indexvar->GetNdata();
00377             break;
00378          case  1:
00379             vsize = -1;
00380             break;
00381       };
00382    } else vsize = size;
00383 
00384    fCumulSizes[code][fNdimensions[code]] = size;
00385 
00386    if ( fIndexes[code][fNdimensions[code]] < 0 ) {
00387       fManager->UpdateUsedSize(virt_dim, vsize);
00388    }
00389 
00390    fNdimensions[code] ++;
00391 
00392 }
00393 
00394 //______________________________________________________________________________
00395 Int_t TTreeFormula::RegisterDimensions(const char *info, Int_t code)
00396 {
00397    // This method is used internally to decode the dimensions of the variables
00398 
00399    // We assume that there are NO white spaces in the info string
00400    const char * current;
00401    Int_t size, scanindex, vardim;
00402 
00403    current = info;
00404    vardim = 0;
00405    // the next value could be before the string but
00406    // that's okay because the next operation is ++
00407    // (this is to avoid (?) a if statement at the end of the
00408    // loop)
00409    if (current[0] != '[') current--;
00410    while (current) {
00411       current++;
00412       scanindex = sscanf(current,"%d",&size);
00413       // if scanindex is 0 then we have a name index thus a variable
00414       // array (or TClonesArray!).
00415 
00416       if (scanindex==0) size = -1;
00417 
00418       vardim += RegisterDimensions(code, size);
00419 
00420       if (fNdimensions[code] >= kMAXFORMDIM) {
00421          // NOTE: test that fNdimensions[code] is NOT too big!!
00422 
00423          break;
00424       }
00425       current = (char*)strstr( current, "[" );
00426    }
00427    return vardim;
00428 }
00429 
00430 
00431 //______________________________________________________________________________
00432 Int_t TTreeFormula::RegisterDimensions(Int_t code, Int_t size, TFormLeafInfoMultiVarDim * multidim) {
00433    // This method stores the dimension information for later usage.
00434 
00435    TDimensionInfo * info = new TDimensionInfo(code,fNoper,size,multidim);
00436    fDimensionSetup->Add(info);
00437    fCumulSizes[code][fNdimensions[code]] = size;
00438    fNdimensions[code] ++;
00439    return (size==-1) ? 1 : 0;
00440 }
00441 
00442 //______________________________________________________________________________
00443 Int_t TTreeFormula::RegisterDimensions(Int_t code, TFormLeafInfo *leafinfo,
00444                                        TFormLeafInfo * /* maininfo */,
00445                                        Bool_t useCollectionObject) {
00446    // This method is used internally to decode the dimensions of the variables
00447 
00448    Int_t ndim, size, current, vardim;
00449    vardim = 0;
00450 
00451    const TStreamerElement * elem = leafinfo->fElement;
00452    TClass* c = elem ? elem->GetClassPointer() : 0;
00453 
00454    TFormLeafInfoMultiVarDim * multi = dynamic_cast<TFormLeafInfoMultiVarDim * >(leafinfo);
00455    if (multi) {
00456       // We have a second variable dimensions
00457       fManager->EnableMultiVarDims();
00458       multi->fDim = fNdimensions[code];
00459       return RegisterDimensions(code, -1, multi);
00460    }
00461    if (elem->IsA() == TStreamerBasicPointer::Class()) {
00462 
00463       if (elem->GetArrayDim()>0) {
00464 
00465          ndim = elem->GetArrayDim();
00466          size = elem->GetMaxIndex(0);
00467          vardim += RegisterDimensions(code, -1);
00468       } else {
00469          ndim = 1;
00470          size = -1;
00471       }
00472 
00473       TStreamerBasicPointer *array = (TStreamerBasicPointer*)elem;
00474       TClass *cl = leafinfo->fClass;
00475       Int_t offset;
00476       TStreamerElement* counter = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(array->GetCountName(),offset);
00477 #if 1
00478       leafinfo->fCounter = new TFormLeafInfo(cl,offset,counter);
00479 #else /* Code is not ready yet see revision 14078 */
00480       if (maininfo==0 || maininfo==leafinfo || 1) {
00481          leafinfo->fCounter = new TFormLeafInfo(cl,offset,counter);
00482       } else {
00483          leafinfo->fCounter = maininfo->DeepCopy();
00484          TFormLeafInfo *currentinfo = leafinfo->fCounter;
00485          while(currentinfo->fNext && currentinfo->fNext->fNext) currentinfo=currentinfo->fNext;
00486          delete currentinfo->fNext;
00487          currentinfo->fNext = new TFormLeafInfo(cl,offset,counter);
00488       }
00489 #endif
00490    } else if (!useCollectionObject && elem->GetClassPointer() == TClonesArray::Class() ) {
00491 
00492       ndim = 1;
00493       size = -1;
00494 
00495       TClass * clonesClass = TClonesArray::Class();
00496       Int_t c_offset;
00497       TStreamerElement *counter = ((TStreamerInfo*)clonesClass->GetStreamerInfo())->GetStreamerElement("fLast",c_offset);
00498       leafinfo->fCounter = new TFormLeafInfo(clonesClass,c_offset,counter);
00499 
00500    } else if (!useCollectionObject && elem->GetClassPointer() && elem->GetClassPointer()->GetCollectionProxy() ) {
00501 
00502       if ( typeid(*leafinfo) == typeid(TFormLeafInfoCollection) ) {
00503          ndim = 1;
00504          size = -1;
00505       } else {
00506          R__ASSERT( fHasMultipleVarDim[code] );
00507          ndim = 1;
00508          size = 1;
00509       }
00510 
00511    } else if ( c && c->GetReferenceProxy() && c->GetReferenceProxy()->HasCounter() ) {
00512       ndim = 1;
00513       size = -1;
00514    } else if (elem->GetArrayDim()>0) {
00515 
00516       ndim = elem->GetArrayDim();
00517       size = elem->GetMaxIndex(0);
00518 
00519    } else if ( elem->GetNewType()== TStreamerInfo::kCharStar) {
00520 
00521       // When we implement being able to read the length from
00522       // strlen, we will have:
00523       // ndim = 1;
00524       // size = -1;
00525       // until then we more or so die:
00526       ndim = 1;
00527       size = 1; //NOTE: changed from 0
00528 
00529    } else return 0;
00530 
00531    current = 0;
00532    do {
00533       vardim += RegisterDimensions(code, size);
00534 
00535       if (fNdimensions[code] >= kMAXFORMDIM) {
00536          // NOTE: test that fNdimensions[code] is NOT too big!!
00537 
00538          break;
00539       }
00540       current++;
00541       size = elem->GetMaxIndex(current);
00542    } while (current<ndim);
00543 
00544    return vardim;
00545 }
00546 
00547 //______________________________________________________________________________
00548 Int_t TTreeFormula::RegisterDimensions(Int_t code, TBranchElement *branch) {
00549    // This method is used internally to decode the dimensions of the variables
00550 
00551    TBranchElement * leafcount2 = branch->GetBranchCount2();
00552    if (leafcount2) {
00553       // With have a second variable dimensions
00554       TBranchElement *leafcount = dynamic_cast<TBranchElement*>(branch->GetBranchCount());
00555 
00556       R__ASSERT(leafcount); // The function should only be called on a functional TBranchElement object
00557 
00558       fManager->EnableMultiVarDims();
00559       TFormLeafInfoMultiVarDim * info = new TFormLeafInfoMultiVarDimDirect();
00560       fDataMembers.AddAtAndExpand(info, code);
00561       fHasMultipleVarDim[code] = kTRUE;
00562 
00563       info->fCounter = new TFormLeafInfoDirect(leafcount);
00564       info->fCounter2 = new TFormLeafInfoDirect(leafcount2);
00565       info->fDim = fNdimensions[code];
00566       //if (fIndexes[code][info->fDim]<0) {
00567       //  info->fVirtDim = virt_dim;
00568       //  if (!fVarDims[virt_dim]) fVarDims[virt_dim] = new TArrayI;
00569       //}
00570       return RegisterDimensions(code, -1, info);
00571    }
00572    return 0;
00573 }
00574 
00575 //______________________________________________________________________________
00576 Int_t TTreeFormula::RegisterDimensions(Int_t code, TLeaf *leaf) {
00577    // This method is used internally to decode the dimensions of the variables
00578 
00579    Int_t numberOfVarDim = 0;
00580 
00581    // Let see if we can understand the structure of this branch.
00582    // Usually we have: leafname[fixed_array] leaftitle[var_array]\type
00583    // (with fixed_array that can be a multi-dimension array.
00584    const char *tname = leaf->GetTitle();
00585    char *leaf_dim = (char*)strstr( tname, "[" );
00586 
00587    const char *bname = leaf->GetBranch()->GetName();
00588    char *branch_dim = (char*)strstr(bname,"[");
00589    if (branch_dim) branch_dim++; // skip the '['
00590 
00591    Bool_t isString  = kFALSE;
00592    if  (leaf->IsA() == TLeafElement::Class()) {
00593       Int_t type =((TBranchElement*)leaf->GetBranch())->GetStreamerType();
00594       isString =    (type == TStreamerInfo::kOffsetL+TStreamerInfo::kChar)
00595                  || (type == TStreamerInfo::kCharStar);
00596    } else {
00597       isString = (leaf->IsA() == TLeafC::Class());
00598    }
00599    if (leaf_dim) {
00600       leaf_dim++; // skip the '['
00601       if (!branch_dim || strncmp(branch_dim,leaf_dim,strlen(branch_dim))) {
00602          // then both are NOT the same so do the leaf title first:
00603          numberOfVarDim += RegisterDimensions( leaf_dim, code);
00604       } else if (branch_dim && strncmp(branch_dim,leaf_dim,strlen(branch_dim))==0
00605                  && strlen(leaf_dim)>strlen(branch_dim)
00606                  && (leaf_dim+strlen(branch_dim))[0]=='[') {
00607          // we have extra info in the leaf title
00608          numberOfVarDim += RegisterDimensions( leaf_dim+strlen(branch_dim)+1, code);
00609       }
00610    }
00611    if (branch_dim) {
00612       // then both are NOT same so do the branch name next:
00613       if (isString) {
00614          numberOfVarDim += RegisterDimensions( code, 1);            
00615       } else {
00616          numberOfVarDim += RegisterDimensions( branch_dim, code);
00617       }
00618    }
00619    if (leaf->IsA() == TLeafElement::Class()) {
00620       TBranchElement* branch = (TBranchElement*) leaf->GetBranch();
00621       if (branch->GetBranchCount2()) {
00622 
00623          if (!branch->GetBranchCount()) {
00624             Warning("DefinedVariable",
00625                     "Noticed an incorrect in-memory TBranchElement object (%s).\nIt has a BranchCount2 but no BranchCount!\nThe result might be incorrect!",
00626                     branch->GetName());
00627             return numberOfVarDim;
00628          }
00629 
00630          // Switch from old direct style to using a TLeafInfo
00631          if (fLookupType[code] == kDataMember)
00632             Warning("DefinedVariable",
00633                     "Already in kDataMember mode when handling multiple variable dimensions");
00634          fLookupType[code] = kDataMember;
00635 
00636          // Feed the information into the Dimensions system
00637          numberOfVarDim += RegisterDimensions( code, branch);
00638 
00639       }
00640    }
00641    return numberOfVarDim;
00642 }
00643 
00644 //______________________________________________________________________________
00645 Int_t TTreeFormula::DefineAlternate(const char *expression)
00646 {
00647    // This method check for treat the case where expression contains $Atl and load up
00648    // both fAliases and fExpr.
00649    // We return
00650    //   -1 in case of failure
00651    //   0 in case we did not find $Alt
00652    //   the action number in case of success.
00653 
00654    static const char *altfunc = "Alt$(";
00655    static const char *minfunc = "MinIf$(";
00656    static const char *maxfunc = "MaxIf$(";
00657    Int_t action = 0;
00658    Int_t start = 0;
00659    
00660    if (   strncmp(expression,altfunc,strlen(altfunc))==0
00661        && expression[strlen(expression)-1]==')' ) {
00662       action = kAlternate;
00663       start = strlen(altfunc);
00664    }
00665    if (   strncmp(expression,maxfunc,strlen(maxfunc))==0
00666        && expression[strlen(expression)-1]==')' ) {
00667       action = kMaxIf;
00668       start = strlen(maxfunc);
00669    }
00670    if (   strncmp(expression,minfunc,strlen(minfunc))==0
00671        && expression[strlen(expression)-1]==')' ) {
00672       action = kMinIf;
00673       start = strlen(minfunc);
00674    }
00675    
00676    if (action) {
00677       TString full = expression;
00678       TString part1;
00679       TString part2;
00680       int paran = 0;
00681       int instr = 0;
00682       int brack = 0;
00683       for(unsigned int i=start;i<strlen(expression);++i) {
00684          switch (expression[i]) {
00685             case '(': paran++; break;
00686             case ')': paran--; break;
00687             case '"': instr = instr ? 0 : 1; break;
00688             case '[': brack++; break;
00689             case ']': brack--; break;
00690          };
00691          if (expression[i]==',' && paran==0 && instr==0 && brack==0) {
00692             part1 = full( start, i-start );
00693             part2 = full( i+1, full.Length() -1 - (i+1) );
00694             break; // out of the for loop
00695          }
00696       }
00697       if (part1.Length() && part2.Length()) {
00698          TTreeFormula *primary = new TTreeFormula("primary",part1,fTree);
00699          TTreeFormula *alternate = new TTreeFormula("alternate",part2,fTree);
00700 
00701          short isstring = 0;
00702 
00703          if (action == kAlternate) {
00704             if (alternate->GetManager()->GetMultiplicity() != 0 ) {
00705                Error("DefinedVariable","The 2nd arguments in %s can not be an array (%s,%d)!",
00706                      expression,alternate->GetTitle(),
00707                      alternate->GetManager()->GetMultiplicity());
00708                return -1;
00709             }
00710 
00711             // Should check whether we have strings.
00712             if (primary->IsString()) {
00713                if (!alternate->IsString()) {
00714                   Error("DefinedVariable",
00715                         "The 2nd arguments in %s has to return the same type as the 1st argument (string)!",
00716                         expression);
00717                   return -1;
00718                }
00719                isstring = 1;
00720             } else if (alternate->IsString()) {
00721                Error("DefinedVariable",
00722                      "The 2nd arguments in %s has to return the same type as the 1st argument (numerical type)!",
00723                      expression);
00724                return -1;
00725             }
00726          } else {
00727             primary->GetManager()->Add( alternate );
00728             primary->GetManager()->Sync();
00729             if (primary->IsString() || alternate->IsString()) {
00730                if (!alternate->IsString()) {
00731                   Error("DefinedVariable",
00732                         "The arguments of %s can not be strings!",
00733                         expression);
00734                   return -1;
00735                }
00736             }
00737          }
00738 
00739          fAliases.AddAtAndExpand(primary,fNoper);
00740          fExpr[fNoper] = "";
00741          SetAction(fNoper, (Int_t)action + isstring, 0 );
00742          ++fNoper;
00743 
00744          fAliases.AddAtAndExpand(alternate,fNoper);
00745          return (Int_t)kAlias + isstring;
00746       }
00747    }
00748    return 0;
00749 }
00750 
00751 //______________________________________________________________________________
00752 Int_t TTreeFormula::ParseWithLeaf(TLeaf* leaf, const char* subExpression, Bool_t final, UInt_t paran_level, TObjArray& castqueue, Bool_t useLeafCollectionObject, const char* fullExpression)
00753 {
00754    // Decompose 'expression' as pointing to something inside the leaf
00755    // Returns:
00756    //   -2  Error: some information is missing (message already printed)
00757    //   -1  Error: Syntax is incorrect (message already printed)
00758    //    0
00759    //    >0 the value returns is the action code.
00760 
00761    Int_t action = 0;
00762 
00763    Int_t numberOfVarDim = 0;
00764    char *current;
00765 
00766    char  scratch[kMaxLen]; scratch[0] = '\0';
00767    char     work[kMaxLen];    work[0] = '\0';
00768 
00769    const char *right = subExpression;
00770    TString name = fullExpression;
00771 
00772    TBranch *branch = leaf ? leaf->GetBranch() : 0;
00773    Long64_t readentry = fTree->GetTree()->GetReadEntry();
00774    if (readentry==-1) readentry=0;
00775 
00776    Bool_t useLeafReferenceObject = false;
00777    Int_t code = fNcodes-1;
00778 
00779    // Make a check to prevent problem with some corrupted files (missing TStreamerInfo).
00780    if (leaf && leaf->IsA()==TLeafElement::Class()) {
00781       TBranchElement *br = 0;
00782       if( branch->IsA() ==  TBranchElement::Class() )
00783       {
00784          br = ((TBranchElement*)branch);
00785 
00786          if ( br->GetInfo() == 0 ) {
00787             Error("DefinedVariable","Missing StreamerInfo for %s.  We will be unable to read!",
00788                   name.Data());
00789             return -2;
00790          }
00791       }
00792 
00793       TBranch *bmom = branch->GetMother();
00794       if( bmom->IsA() == TBranchElement::Class() )
00795       {
00796          TBranchElement *mom = (TBranchElement*)br->GetMother();
00797          if (mom!=br) {
00798             if (mom->GetInfo()==0) {
00799                Error("DefinedVariable","Missing StreamerInfo for %s."
00800                      "  We will be unable to read!",
00801                      mom->GetName());
00802                return -2;
00803             }
00804             if ((mom->GetType()) < -1 && !mom->GetAddress()) {
00805                Error("DefinedVariable", "Address not set when the type of the branch is negative for for %s.  We will be unable to read!", mom->GetName());
00806                return -2;
00807             }
00808          }
00809       }
00810    }
00811 
00812    // We need to record the location in the list of leaves because
00813    // the tree might actually be a chain and in that case the leaf will
00814    // change from tree to tree!.
00815 
00816    // Let's reconstruct the name of the leaf, including the possible friend alias
00817    TTree *realtree = fTree->GetTree();
00818    const char* alias = 0;
00819    if (leaf) {
00820       if (realtree) alias = realtree->GetFriendAlias(leaf->GetBranch()->GetTree());
00821       if (!alias && realtree!=fTree) {
00822          // Let's try on the chain
00823          alias = fTree->GetFriendAlias(leaf->GetBranch()->GetTree());
00824       }
00825    }
00826    if (alias) snprintf(scratch,kMaxLen-1,"%s.%s",alias,leaf->GetName());
00827    else if (leaf) strlcpy(scratch,leaf->GetName(),kMaxLen);
00828 
00829    TTree *tleaf = realtree;
00830    if (leaf) {
00831       tleaf = leaf->GetBranch()->GetTree();
00832       fCodes[code] = tleaf->GetListOfLeaves()->IndexOf(leaf);
00833       const char *mother_name = leaf->GetBranch()->GetMother()->GetName();
00834       TString br_extended_name; // Could do ( strlen(mother_name)+strlen( leaf->GetBranch()->GetName() ) + 2 )
00835       if (leaf->GetBranch()!=leaf->GetBranch()->GetMother()) {
00836          if (mother_name[strlen(mother_name)-1]!='.') {
00837             br_extended_name = mother_name;
00838             br_extended_name.Append('.');
00839          }
00840       }
00841       br_extended_name.Append( leaf->GetBranch()->GetName() );
00842       Ssiz_t dim = br_extended_name.First('[');
00843       if (dim >= 0) br_extended_name.Remove(dim);
00844 
00845       TNamed *named = new TNamed(scratch,br_extended_name.Data());
00846       fLeafNames.AddAtAndExpand(named,code);
00847       fLeaves.AddAtAndExpand(leaf,code);
00848    }
00849 
00850    // If the leaf belongs to a friend tree which has an index, we might
00851    // be in the case where some entry do not exist.
00852    if (tleaf != realtree && tleaf->GetTreeIndex()) {
00853       // reset the multiplicity
00854       if (fMultiplicity >= 0) fMultiplicity = 1;
00855    }
00856 
00857    // Analyze the content of 'right'
00858 
00859    // Try to find out the class (if any) of the object in the leaf.
00860    TClass * cl = 0;
00861    TFormLeafInfo *maininfo = 0;
00862    TFormLeafInfo *previnfo = 0;
00863    Bool_t unwindCollection = kFALSE;
00864    static TClassRef stdStringClass = TClass::GetClass("string");
00865 
00866    if (leaf==0) {
00867       TNamed *names = (TNamed*)fLeafNames.UncheckedAt(code);
00868       fLeafNames.AddAt(0,code);
00869       TTree *what = (TTree*)fLeaves.UncheckedAt(code);
00870       fLeaves.AddAt(0,code);
00871 
00872       cl = what ? what->IsA() : TTree::Class();
00873       maininfo = new TFormLeafInfoTTree(fTree,names->GetName(),what);
00874       previnfo = maininfo;
00875 
00876       delete names;
00877    } else if (leaf->InheritsFrom(TLeafObject::Class()) ) {
00878       TBranchObject *bobj = (TBranchObject*)leaf->GetBranch();
00879       cl = TClass::GetClass(bobj->GetClassName());
00880    } else if (leaf->InheritsFrom(TLeafElement::Class())) {
00881       TBranchElement *branchEl = (TBranchElement *)leaf->GetBranch();
00882       branchEl->SetupAddresses();
00883       TStreamerInfo *info = branchEl->GetInfo();
00884       TStreamerElement *element = 0;
00885       Int_t type = branchEl->GetStreamerType();
00886       switch(type) {
00887          case TStreamerInfo::kBase:
00888          case TStreamerInfo::kObject:
00889          case TStreamerInfo::kTString:
00890          case TStreamerInfo::kTNamed:
00891          case TStreamerInfo::kTObject:
00892          case TStreamerInfo::kAny:
00893          case TStreamerInfo::kAnyP:
00894          case TStreamerInfo::kAnyp:
00895          case TStreamerInfo::kSTL:
00896          case TStreamerInfo::kSTLp:
00897          case TStreamerInfo::kObjectp:
00898          case TStreamerInfo::kObjectP: {
00899             element = (TStreamerElement *)info->GetElems()[branchEl->GetID()];
00900             if (element) cl = element->GetClassPointer();
00901          }
00902          break;
00903          case TStreamerInfo::kOffsetL + TStreamerInfo::kSTL:
00904          case TStreamerInfo::kOffsetL + TStreamerInfo::kSTLp:
00905          case TStreamerInfo::kOffsetL + TStreamerInfo::kAny:
00906          case TStreamerInfo::kOffsetL + TStreamerInfo::kAnyp:
00907          case TStreamerInfo::kOffsetL + TStreamerInfo::kAnyP:
00908          case TStreamerInfo::kOffsetL + TStreamerInfo::kObjectp:
00909          case TStreamerInfo::kOffsetL + TStreamerInfo::kObjectP:
00910          case TStreamerInfo::kOffsetL + TStreamerInfo::kObject:  {
00911             element = (TStreamerElement *)info->GetElems()[branchEl->GetID()];
00912             if (element){
00913                cl = element->GetClassPointer();
00914             }
00915          }
00916          break;
00917          case -1: {
00918             cl = info->GetClass();
00919          }
00920          break;
00921       }
00922 
00923       // If we got a class object, we need to verify whether it is on a
00924       // split TClonesArray sub branch.
00925       if (cl && branchEl->GetBranchCount()) {
00926          if (branchEl->GetType()==31) {
00927             // This is inside a TClonesArray.
00928 
00929             if (!element) {
00930                Warning("DefineVariable",
00931                        "Missing TStreamerElement in object in TClonesArray section");
00932                return -2;
00933             }
00934             TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(cl, 0, element, kTRUE);
00935 
00936             // The following code was commmented out because in THIS case
00937             // the dimension are actually handled by parsing the title and name of the leaf
00938             // and branch (see a little further)
00939             // The dimension needs to be handled!
00940             // numberOfVarDim += RegisterDimensions(code,clonesinfo);
00941 
00942             maininfo = clonesinfo;
00943 
00944             // We skip some cases because we can assume we have an object.
00945             Int_t offset=0;
00946             info->GetStreamerElement(element->GetName(),offset);
00947             if (type == TStreamerInfo::kObjectp ||
00948                   type == TStreamerInfo::kObjectP ||
00949                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kObjectp ||
00950                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kObjectP ||
00951                   type == TStreamerInfo::kSTLp ||
00952                   type == TStreamerInfo::kAnyp ||
00953                   type == TStreamerInfo::kAnyP ||
00954                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kSTLp ||
00955                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kAnyp ||
00956                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kAnyP) {
00957                previnfo = new TFormLeafInfoPointer(cl,offset+branchEl->GetOffset(),element);
00958             } else {
00959                previnfo = new TFormLeafInfo(cl,offset+branchEl->GetOffset(),element);
00960             }
00961             maininfo->fNext = previnfo;
00962             unwindCollection = kTRUE;
00963 
00964          } else if (branchEl->GetType()==41) {
00965 
00966             // This is inside a Collection
00967 
00968             if (!element) {
00969                Warning("DefineVariable","Missing TStreamerElement in object in Collection section");
00970                return -2;
00971             }
00972             // First we need to recover the collection.
00973             TBranchElement *count = branchEl->GetBranchCount();
00974             TFormLeafInfo* collectioninfo;
00975             if ( count->GetID() >= 0 ) {
00976                TStreamerElement *collectionElement =
00977                   (TStreamerElement *)count->GetInfo()->GetElems()[count->GetID()];
00978                TClass *collectionCl = collectionElement->GetClassPointer();
00979 
00980                collectioninfo =
00981                   new TFormLeafInfoCollection(collectionCl, 0, collectionElement, kTRUE);
00982             } else {
00983                TClass *collectionCl = TClass::GetClass(count->GetClassName());
00984                collectioninfo =
00985                   new TFormLeafInfoCollection(collectionCl, 0, collectionCl, kTRUE);
00986             }
00987 
00988             // The following code was commmented out because in THIS case
00989             // the dimension are actually handled by parsing the title and name of the leaf
00990             // and branch (see a little further)
00991             // The dimension needs to be handled!
00992             // numberOfVarDim += RegisterDimensions(code,clonesinfo);
00993 
00994             maininfo = collectioninfo;
00995 
00996             // We skip some cases because we can assume we have an object.
00997             Int_t offset=0;
00998             info->GetStreamerElement(element->GetName(),offset);
00999             if (type == TStreamerInfo::kObjectp ||
01000                   type == TStreamerInfo::kObjectP ||
01001                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kObjectp ||
01002                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kObjectP ||
01003                   type == TStreamerInfo::kSTLp ||
01004                   type == TStreamerInfo::kAnyp ||
01005                   type == TStreamerInfo::kAnyP ||
01006                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kSTLp ||
01007                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kAnyp ||
01008                   type == TStreamerInfo::kOffsetL + TStreamerInfo::kAnyP) {
01009                previnfo = new TFormLeafInfoPointer(cl,offset+branchEl->GetOffset(),element);
01010             } else {
01011                previnfo = new TFormLeafInfo(cl,offset+branchEl->GetOffset(),element);
01012             }
01013             maininfo->fNext = previnfo;
01014             unwindCollection = kTRUE;
01015          }
01016       } else if ( branchEl->GetType()==3) {
01017          TFormLeafInfo* clonesinfo;
01018          if (useLeafCollectionObject) {
01019             clonesinfo = new TFormLeafInfoCollectionObject(cl);
01020          } else {
01021             clonesinfo = new TFormLeafInfoClones(cl, 0, kTRUE);
01022             // The dimension needs to be handled!
01023             numberOfVarDim += RegisterDimensions(code,clonesinfo,maininfo,useLeafCollectionObject);
01024 
01025          }
01026          maininfo = clonesinfo;
01027          previnfo = maininfo;
01028 
01029       } else if (!useLeafCollectionObject && branchEl->GetType()==4) {
01030 
01031          TFormLeafInfo* collectioninfo;
01032          if (useLeafCollectionObject) {
01033             collectioninfo = new TFormLeafInfoCollectionObject(cl);
01034          } else {
01035             collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, kTRUE);
01036             // The dimension needs to be handled!
01037             numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,useLeafCollectionObject);
01038          }
01039 
01040          maininfo = collectioninfo;
01041          previnfo = maininfo;
01042 
01043       } else if (branchEl->GetStreamerType()==-1 && cl && cl->GetCollectionProxy()) {
01044 
01045          if (useLeafCollectionObject) {
01046 
01047             TFormLeafInfo *collectioninfo = new TFormLeafInfoCollectionObject(cl);
01048             maininfo = collectioninfo;
01049             previnfo = collectioninfo;
01050 
01051          } else {
01052             TFormLeafInfo *collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, kTRUE);
01053             // The dimension needs to be handled!
01054             numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
01055 
01056             maininfo = collectioninfo;
01057             previnfo = collectioninfo;
01058 
01059             if (cl->GetCollectionProxy()->GetValueClass()!=0 &&
01060                 cl->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()!=0) {
01061 
01062                TFormLeafInfo *multi = new TFormLeafInfoMultiVarDimCollection(cl,0,
01063                      cl->GetCollectionProxy()->GetValueClass(),collectioninfo);
01064 
01065                fHasMultipleVarDim[code] = kTRUE;
01066                numberOfVarDim += RegisterDimensions(code,multi,maininfo,kFALSE);
01067                previnfo->fNext = multi;
01068                cl = cl->GetCollectionProxy()->GetValueClass();
01069                multi->fNext =  new TFormLeafInfoCollection(cl, 0, cl, false);
01070                previnfo = multi->fNext;
01071 
01072             }
01073             if (cl->GetCollectionProxy()->GetValueClass()==0 &&
01074                 cl->GetCollectionProxy()->GetType()>0) {
01075 
01076                previnfo->fNext =
01077                         new TFormLeafInfoNumerical(cl->GetCollectionProxy());
01078                previnfo = previnfo->fNext;
01079             } else {
01080                // nothing to do
01081             }
01082          }
01083 
01084       } else if (strlen(right)==0 && cl && element && final) {
01085 
01086          TClass *elemCl = element->GetClassPointer();
01087          if (!useLeafCollectionObject
01088              && elemCl && elemCl->GetCollectionProxy()
01089              && elemCl->GetCollectionProxy()->GetValueClass()
01090              && elemCl->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()) {
01091 
01092             TFormLeafInfo *collectioninfo =
01093                new TFormLeafInfoCollection(cl, 0, elemCl);
01094 
01095             // The dimension needs to be handled!
01096             numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
01097 
01098             maininfo = collectioninfo;
01099             previnfo = collectioninfo;
01100 
01101             TFormLeafInfo *multi =
01102                new TFormLeafInfoMultiVarDimCollection(elemCl, 0,
01103                                                       elemCl->GetCollectionProxy()->GetValueClass(),
01104                                                       collectioninfo);
01105 
01106             fHasMultipleVarDim[code] = kTRUE;
01107             numberOfVarDim += RegisterDimensions(code,multi,maininfo,kFALSE);
01108             previnfo->fNext = multi;
01109             cl = elemCl->GetCollectionProxy()->GetValueClass();
01110             multi->fNext =  new TFormLeafInfoCollection(cl, 0, cl, false);
01111             previnfo = multi->fNext;
01112 
01113             if (cl->GetCollectionProxy()->GetValueClass()==0 &&
01114                 cl->GetCollectionProxy()->GetType()>0) {
01115 
01116                previnfo->fNext =
01117                   new TFormLeafInfoNumerical(cl->GetCollectionProxy());
01118                previnfo = previnfo->fNext;
01119             }
01120 
01121          } else if (!useLeafCollectionObject
01122                && elemCl && elemCl->GetCollectionProxy()
01123                && elemCl->GetCollectionProxy()->GetValueClass()==0
01124                && elemCl->GetCollectionProxy()->GetType()>0) {
01125 
01126             // At this point we have an element which is inside a class (which is not
01127             // a collection) and this element of a collection of numerical type.
01128             // (Note: it is not possible to have more than one variable dimension
01129             //  unless we were supporting variable size C-style array of collection).
01130 
01131             TFormLeafInfo* collectioninfo =
01132                new TFormLeafInfoCollection(cl, 0, elemCl);
01133 
01134             // The dimension needs to be handled!
01135             numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
01136 
01137             collectioninfo->fNext =
01138                new TFormLeafInfoNumerical(elemCl->GetCollectionProxy());
01139 
01140             maininfo = collectioninfo;
01141             previnfo = maininfo->fNext;
01142 
01143          }  else if (!useLeafCollectionObject
01144                      && elemCl && elemCl->GetCollectionProxy()) {
01145             if (elemCl->GetCollectionProxy()->GetValueClass()==TString::Class()) {
01146                right = "Data()";
01147             } else if (elemCl->GetCollectionProxy()->GetValueClass()==stdStringClass) {
01148                right = "c_str()";
01149             }
01150 
01151          } else if (!element->IsaPointer()) {
01152             
01153             maininfo = new TFormLeafInfoDirect(branchEl);
01154             previnfo = maininfo;
01155             
01156          }
01157       }
01158       else if ( cl && cl->GetReferenceProxy() )  {
01159          if ( useLeafCollectionObject || fullExpression[0] == '@' || fullExpression[strlen(scratch)] == '@' ) {
01160             useLeafReferenceObject = true;
01161          }
01162          else  {
01163             if ( !maininfo )  {
01164                maininfo = previnfo = new TFormLeafInfoReference(cl, element, 0);
01165                numberOfVarDim += RegisterDimensions(code,maininfo,maininfo,kFALSE);
01166             }
01167             cl = 0;
01168             for(int i=0; i<leaf->GetBranch()->GetEntries()-readentry; ++i)  {
01169                R__LoadBranch(leaf->GetBranch(), readentry+i, fQuickLoad);
01170                cl = ((TFormLeafInfoReference*)maininfo)->GetValueClass(leaf);
01171                if ( cl ) break;
01172             }
01173             if ( !cl )  {
01174                Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
01175                return -1;
01176             }
01177          }
01178       }
01179    }
01180 
01181    // Treat the dimension information in the leaf name, title and 2nd branch count
01182    if (leaf) numberOfVarDim += RegisterDimensions(code,leaf);
01183 
01184    if (cl) {
01185       if (unwindCollection) {
01186          // So far we should get here only if we encounter a split collection of a class that contains
01187          // directly a collection.
01188          R__ASSERT(numberOfVarDim==1 && maininfo);
01189 
01190          if (!useLeafCollectionObject && cl && cl->GetCollectionProxy()) {
01191             TFormLeafInfo *multi =
01192                new TFormLeafInfoMultiVarDimCollection(cl, 0, cl, maininfo);
01193             fHasMultipleVarDim[code] = kTRUE;
01194             numberOfVarDim += RegisterDimensions(code,multi,maininfo,kFALSE);
01195             previnfo->fNext = multi;
01196 
01197             multi->fNext =  new TFormLeafInfoCollection(cl, 0, cl, false);
01198             previnfo = multi->fNext;
01199 
01200             if (cl->GetCollectionProxy()->GetValueClass()==0 &&
01201                 cl->GetCollectionProxy()->GetType()>0) {
01202 
01203                previnfo->fNext =
01204                   new TFormLeafInfoNumerical(cl->GetCollectionProxy());
01205                previnfo = previnfo->fNext;
01206             }
01207          } else if (!useLeafCollectionObject && cl == TClonesArray::Class()) {
01208 
01209             TFormLeafInfo *multi =
01210                new TFormLeafInfoMultiVarDimClones(cl, 0, cl, maininfo);
01211             fHasMultipleVarDim[code] = kTRUE;
01212             numberOfVarDim += RegisterDimensions(code,multi,maininfo,kFALSE);
01213             previnfo->fNext = multi;
01214 
01215             multi->fNext =  new TFormLeafInfoClones(cl, 0, false);
01216             previnfo = multi->fNext;
01217          }
01218       }
01219       Int_t offset=0;
01220       Int_t nchname = strlen(right);
01221       TFormLeafInfo *leafinfo = 0;
01222       TStreamerElement* element = 0;
01223 
01224       // Let see if the leaf was attempted to be casted.
01225       // Since there would have been something like
01226       // ((cast_class*)leafname)->....  we need to use
01227       // paran_level+1
01228       // Also we disable this functionality in case of TClonesArray
01229       // because it is not yet allowed to have 'inheritance' (or virtuality)
01230       // in play in a TClonesArray.
01231       {
01232          TClass * casted = (TClass*) castqueue.At(paran_level+1);
01233          if (casted && cl != TClonesArray::Class()) {
01234             if ( ! casted->InheritsFrom(cl) ) {
01235                Error("DefinedVariable","%s does not inherit from %s.  Casting not possible!",
01236                      casted->GetName(),cl->GetName());
01237                return -2;
01238             }
01239             leafinfo = new TFormLeafInfoCast(cl,casted);
01240             fHasCast = kTRUE;
01241             if (maininfo==0) {
01242                maininfo = leafinfo;
01243             }
01244             if (previnfo==0) {
01245                previnfo = leafinfo;
01246             } else {
01247                previnfo->fNext = leafinfo;
01248                previnfo = leafinfo;
01249             }
01250             leafinfo = 0;
01251             
01252             cl = casted;
01253             castqueue.AddAt(0,paran_level);
01254          }
01255       }
01256       Int_t i;
01257       Bool_t prevUseCollectionObject = useLeafCollectionObject;
01258       Bool_t useCollectionObject = useLeafCollectionObject;
01259       Bool_t useReferenceObject = useLeafReferenceObject;
01260       Bool_t prevUseReferenceObject = useLeafReferenceObject;
01261       for (i=0, current = &(work[0]); i<=nchname;i++ ) {
01262          // We will treated the terminator as a token.
01263          if (right[i] == '(') {
01264             // Right now we do not allow nested paranthesis
01265             do {
01266                *current++ = right[i++];
01267             } while(right[i]!=')' && right[i]);
01268             *current++ = right[i];
01269             *current='\0';
01270             char *params = strchr(work,'(');
01271             if (params) {
01272                *params = 0; params++;
01273             } else params = (char *) ")";
01274             if (cl==0) {
01275                Error("DefinedVariable","Can not call '%s' with a class",work);
01276                return -1;
01277             }
01278             if (cl->GetClassInfo()==0 && !cl->GetCollectionProxy()) {
01279                Error("DefinedVariable","Class probably unavailable:%s",cl->GetName());
01280                return -2;
01281             }
01282             if (!useCollectionObject && cl == TClonesArray::Class()) {
01283                // We are not interested in the ClonesArray object but only
01284                // in its contents.
01285                // We need to retrieve the class of its content.
01286 
01287                TBranch *clbranch = leaf->GetBranch();
01288                R__LoadBranch(clbranch,readentry,fQuickLoad);
01289                TClonesArray * clones;
01290                if (previnfo) clones = (TClonesArray*)previnfo->GetLocalValuePointer(leaf,0);
01291                else {
01292                   Bool_t top = (clbranch==((TBranchElement*)clbranch)->GetMother()
01293                                  || !leaf->IsOnTerminalBranch());
01294                   TClass *mother_cl;
01295                   if (leaf->IsA()==TLeafObject::Class()) {
01296                      // in this case mother_cl is not really used
01297                      mother_cl = cl;
01298                   } else {
01299                      mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
01300                   }
01301                   TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0, top);
01302 
01303                   // The dimension needs to be handled!
01304                   numberOfVarDim += RegisterDimensions(code,clonesinfo,maininfo,kFALSE);
01305 
01306                   previnfo = clonesinfo;
01307                   maininfo = clonesinfo;
01308 
01309                   clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
01310                }
01311                TClass * inside_cl = clones->GetClass();
01312                cl = inside_cl;
01313 
01314             }
01315             else if (!useCollectionObject && cl && cl->GetCollectionProxy() ) {
01316 
01317                // We are NEVER (for now!) interested in the ClonesArray object but only
01318                // in its contents.
01319                // We need to retrieve the class of its content.
01320 
01321                if (previnfo==0) {
01322 
01323                   Bool_t top = (branch==((TBranchElement*)branch)->GetMother()
01324                                  || !leaf->IsOnTerminalBranch());
01325 
01326                   TClass *mother_cl;
01327                   if (leaf->IsA()==TLeafObject::Class()) {
01328                      // in this case mother_cl is not really used
01329                      mother_cl = cl;
01330                   } else {
01331                      mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
01332                   }
01333 
01334                   TFormLeafInfo* collectioninfo =
01335                      new TFormLeafInfoCollection(mother_cl, 0,cl,top);
01336                   // The dimension needs to be handled!
01337                   numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
01338 
01339                   previnfo = collectioninfo;
01340                   maininfo = collectioninfo;
01341 
01342                }
01343 
01344                TClass * inside_cl = cl->GetCollectionProxy()->GetValueClass();
01345                if (inside_cl) cl = inside_cl;
01346                else if (cl->GetCollectionProxy()->GetType()>0) {
01347                   Warning("DefinedVariable","Can not call method on content of %s in %s\n",
01348                            cl->GetName(),name.Data());
01349                   return -2;
01350                }
01351             }
01352             TMethodCall *method  = 0;
01353             if (cl==0) {
01354                Error("DefinedVariable",
01355                      "Could not discover the TClass corresponding to (%s)!",
01356                      right);
01357                return -2;
01358             } else if (cl==TClonesArray::Class() && strcmp(work,"size")==0) {
01359                method = new TMethodCall(cl, "GetEntriesFast", "");
01360             } else if (cl->GetCollectionProxy() && strcmp(work,"size")==0) {
01361                if (maininfo==0) {
01362                   TFormLeafInfo* collectioninfo=0;
01363                   if (useLeafCollectionObject) {
01364 
01365                      Bool_t top = (branch==((TBranchElement*)branch)->GetMother()
01366                                  || !leaf->IsOnTerminalBranch());
01367                      collectioninfo = new TFormLeafInfoCollectionObject(cl,top);
01368                   }
01369                   maininfo=previnfo=collectioninfo;
01370                }
01371                leafinfo = new TFormLeafInfoCollectionSize(cl);
01372                cl = 0;
01373             } else {
01374                if (cl->GetClassInfo()==0) {
01375                   Error("DefinedVariable",
01376                         "Can not call method %s on class without dictionary (%s)!",
01377                         right,cl->GetName());
01378                   return -2;
01379                }
01380                method = new TMethodCall(cl, work, params);
01381             }
01382             if (method) {
01383                if (!method->GetMethod()) {
01384                   Error("DefinedVariable","Unknown method:%s in %s",right,cl->GetName());
01385                   return -1;
01386                }
01387                switch(method->ReturnType()) {
01388                   case TMethodCall::kLong:
01389                      leafinfo = new TFormLeafInfoMethod(cl,method);
01390                      cl = 0;
01391                      break;
01392                   case TMethodCall::kDouble:
01393                      leafinfo = new TFormLeafInfoMethod(cl,method);
01394                      cl = 0;
01395                      break;
01396                   case TMethodCall::kString:
01397                      leafinfo = new TFormLeafInfoMethod(cl,method);
01398                      // 1 will be replaced by -1 when we know how to use strlen
01399                      numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0
01400                      cl = 0;
01401                      break;
01402                   case TMethodCall::kOther:
01403                      {
01404                         TString return_type =
01405                           gInterpreter->TypeName(method->GetMethod()->GetReturnTypeName());
01406                         leafinfo = new TFormLeafInfoMethod(cl,method);
01407                         cl = (return_type == "void") ? 0 : TClass::GetClass(return_type.Data());
01408                      }
01409                      break;
01410                   default:
01411                      Error("DefineVariable","Method %s from %s has an impossible return type %d",
01412                         work,cl->GetName(),method->ReturnType());
01413                      return -2;
01414                }
01415             }
01416             if (maininfo==0) {
01417                maininfo = leafinfo;
01418             }
01419             if (previnfo==0) {
01420                previnfo = leafinfo;
01421             } else {
01422                previnfo->fNext = leafinfo;
01423                previnfo = leafinfo;
01424             }
01425             leafinfo = 0;
01426             current = &(work[0]);
01427             *current = 0;
01428             prevUseCollectionObject = kFALSE;
01429             prevUseReferenceObject = kFALSE;
01430             useCollectionObject = kFALSE;
01431 
01432             if (cl && cl->GetCollectionProxy()) {
01433                if (numberOfVarDim>1) {
01434                   Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections.  Assuming '@' notation for the collection %s.",
01435                      cl->GetName());
01436                   leafinfo = new TFormLeafInfo(cl,0,0);
01437                   useCollectionObject = kTRUE;
01438                } else if (numberOfVarDim==0) {
01439                   R__ASSERT(maininfo);
01440                   leafinfo = new TFormLeafInfoCollection(cl,0,cl);
01441                   numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
01442                } else if (numberOfVarDim==1) {
01443                   R__ASSERT(maininfo);
01444                   leafinfo =
01445                      new TFormLeafInfoMultiVarDimCollection(cl,0,
01446                      (TStreamerElement*)0,maininfo);
01447                   previnfo->fNext = leafinfo;
01448                   previnfo = leafinfo;
01449                   leafinfo = new TFormLeafInfoCollection(cl,0,cl);
01450 
01451                   fHasMultipleVarDim[code] = kTRUE;
01452                   numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
01453                }
01454                previnfo->fNext = leafinfo;
01455                previnfo = leafinfo;
01456                leafinfo = 0;
01457             }
01458             continue;
01459          } else if (right[i] == ')') {
01460             // We should have the end of a cast operator.  Let's introduce a TFormLeafCast
01461             // in the chain.
01462             TClass * casted = (TClass*) ((int(--paran_level)>=0) ? castqueue.At(paran_level) : 0);
01463             if (casted) {
01464                leafinfo = new TFormLeafInfoCast(cl,casted);
01465                fHasCast = kTRUE;
01466 
01467                if (maininfo==0) {
01468                   maininfo = leafinfo;
01469                }
01470                if (previnfo==0) {
01471                   previnfo = leafinfo;
01472                } else {
01473                   previnfo->fNext = leafinfo;
01474                   previnfo = leafinfo;
01475                }
01476                leafinfo = 0;
01477                current = &(work[0]);
01478                *current = 0;
01479 
01480                cl = casted;
01481                continue;
01482 
01483             }
01484          } else if (i > 0 && (right[i] == '.' || right[i] == '[' || right[i] == '\0') ) {
01485             // A delimiter happened let's see if what we have seen
01486             // so far does point to a data member.
01487             Bool_t needClass = kTRUE;
01488             *current = '\0';
01489 
01490             // skip it all if there is nothing to look at
01491             if (strlen(work)==0) continue;
01492 
01493             prevUseCollectionObject = useCollectionObject;
01494             prevUseReferenceObject = useReferenceObject;
01495             if (work[0]=='@') {
01496                useReferenceObject = kTRUE;
01497                useCollectionObject = kTRUE;
01498                Int_t l = 0;
01499                for(l=0;work[l+1]!=0;++l) work[l] = work[l+1];
01500                work[l] = '\0';
01501             } else if (work[strlen(work)-1]=='@') {
01502                useReferenceObject = kTRUE;
01503                useCollectionObject = kTRUE;
01504                work[strlen(work)-1] = '\0';
01505             } else {
01506                useReferenceObject = kFALSE;
01507                useCollectionObject = kFALSE;
01508             }
01509 
01510             Bool_t mustderef = kFALSE;
01511             if ( !prevUseReferenceObject && cl && cl->GetReferenceProxy() )  {
01512                R__LoadBranch(leaf->GetBranch(), readentry, fQuickLoad);
01513                if ( !maininfo )  {
01514                   maininfo = previnfo = new TFormLeafInfoReference(cl, element, offset);
01515                   if ( cl->GetReferenceProxy()->HasCounter() )  {
01516                      numberOfVarDim += RegisterDimensions(code,-1);
01517                   }
01518                   prevUseReferenceObject = kFALSE;
01519                }
01520                needClass = kFALSE;
01521                mustderef = kTRUE;
01522             }
01523             else if (!prevUseCollectionObject && cl == TClonesArray::Class()) {
01524                // We are not interested in the ClonesArray object but only
01525                // in its contents.
01526                // We need to retrieve the class of its content.
01527 
01528                TBranch *clbranch = leaf->GetBranch();
01529                R__LoadBranch(clbranch,readentry,fQuickLoad);
01530                TClonesArray * clones;
01531                if (maininfo) {
01532                   clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
01533                } else {
01534                   // we have a unsplit TClonesArray leaves
01535                   // or we did not yet match any of the sub-branches!
01536 
01537                   TClass *mother_cl;
01538                   if (leaf->IsA()==TLeafObject::Class()) {
01539                      // in this case mother_cl is not really used
01540                      mother_cl = cl;
01541                   } else {
01542                      mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
01543                   }
01544 
01545                   TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0);
01546                   // The dimension needs to be handled!
01547                   numberOfVarDim += RegisterDimensions(code,clonesinfo,maininfo,kFALSE);
01548 
01549                   mustderef = kTRUE;
01550                   previnfo = clonesinfo;
01551                   maininfo = clonesinfo;
01552 
01553                   if (clbranch->GetListOfBranches()->GetLast()>=0) {
01554                      if (clbranch->IsA() != TBranchElement::Class()) {
01555                         Error("DefinedVariable","Unimplemented usage of ClonesArray");
01556                         return -2;
01557                      }
01558                      //clbranch = ((TBranchElement*)clbranch)->GetMother();
01559                      clones = (TClonesArray*)((TBranchElement*)clbranch)->GetObject();
01560                   } else
01561                      clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
01562                }
01563                // NOTE clones can be zero!
01564                if (clones==0) {
01565                   Warning("DefinedVariable",
01566                           "TClonesArray object was not retrievable for %s!",
01567                           name.Data());
01568                   return -1;
01569                }
01570                TClass * inside_cl = clones->GetClass();
01571 #if 1
01572                cl = inside_cl; 
01573 #else
01574 /* Maybe we should make those test lead to warning messages */
01575                if (1 || inside_cl) cl = inside_cl;
01576                // if inside_cl is nul ... we have a problem of inconsistency :(
01577                if (0 && strlen(work)==0) {
01578                   // However in this case we have NO content :(
01579                   // so let get the number of objects
01580                   //strcpy(work,"fLast");
01581                }
01582 #endif
01583             } else if (!prevUseCollectionObject && cl && cl->GetCollectionProxy() ) {
01584 
01585                // We are NEVER interested in the Collection object but only
01586                // in its contents.
01587                // We need to retrieve the class of its content.
01588 
01589                TBranch *clbranch = leaf->GetBranch();
01590                R__LoadBranch(clbranch,readentry,fQuickLoad);
01591 
01592                if (maininfo==0) {
01593 
01594                   // we have a unsplit Collection leaf
01595                   // or we did not yet match any of the sub-branches!
01596 
01597                   TClass *mother_cl;
01598                   if (leaf->IsA()==TLeafObject::Class()) {
01599                      // in this case mother_cl is not really used
01600                      mother_cl = cl;
01601                   } else {
01602                      mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
01603                   }
01604 
01605                   TFormLeafInfo* collectioninfo =
01606                      new TFormLeafInfoCollection(mother_cl, 0, cl);
01607                   // The dimension needs to be handled!
01608                   numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
01609 
01610                   mustderef = kTRUE;
01611                   previnfo = collectioninfo;
01612                   maininfo = collectioninfo;
01613 
01614                } //else if (clbranch->GetStreamerType()==0) {
01615 
01616                //}
01617 
01618                TClass * inside_cl = cl->GetCollectionProxy()->GetValueClass();
01619 
01620                if (!inside_cl && cl->GetCollectionProxy()->GetType() > 0) {
01621                   Warning("DefinedVariable","No data member in content of %s in %s\n",
01622                            cl->GetName(),name.Data());
01623                }
01624                cl = inside_cl;
01625                // if inside_cl is nul ... we have a problem of inconsistency.
01626             }
01627 
01628             if (!cl) {
01629                Warning("DefinedVariable","Missing class for %s!",name.Data());
01630             } else {
01631                element = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(work,offset);
01632             }
01633 
01634             if (!element && !prevUseCollectionObject) {
01635                // We allow for looking for a data member inside a class inside
01636                // a TClonesArray without mentioning the TClonesArrays variable name
01637                TIter next( cl->GetStreamerInfo()->GetElements() );
01638                TStreamerElement * curelem;
01639                while ((curelem = (TStreamerElement*)next())) {
01640                   if (curelem->GetClassPointer() ==  TClonesArray::Class()) {
01641                      Int_t clones_offset;
01642                      ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),clones_offset);
01643                      TFormLeafInfo* clonesinfo =
01644                         new TFormLeafInfo(cl, clones_offset, curelem);
01645                      TClonesArray * clones;
01646                      R__LoadBranch(leaf->GetBranch(),readentry,fQuickLoad);
01647 
01648                      if (previnfo) {
01649                         previnfo->fNext = clonesinfo;
01650                         clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
01651                         previnfo->fNext = 0;
01652                      } else {
01653                         clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
01654                      }
01655 
01656                      TClass *sub_cl = clones->GetClass();
01657                      if (sub_cl) element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(work,offset);
01658                      delete clonesinfo;
01659 
01660                      if (element) {
01661                         leafinfo = new TFormLeafInfoClones(cl,clones_offset,curelem);
01662                         numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
01663                         if (maininfo==0) maininfo = leafinfo;
01664                         if (previnfo==0) previnfo = leafinfo;
01665                         else {
01666                            previnfo->fNext = leafinfo;
01667                            previnfo = leafinfo;
01668                         }
01669                         leafinfo = 0;
01670                         cl = sub_cl;
01671                         break;
01672                      }
01673                   } else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {
01674 
01675                      Int_t coll_offset;
01676                      ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),coll_offset);
01677 
01678                      TClass *sub_cl =
01679                         curelem->GetClassPointer()->GetCollectionProxy()->GetValueClass();
01680                      if (sub_cl) {
01681                         element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(work,offset);
01682                      }
01683                      if (element) {
01684                         if (numberOfVarDim>1) {
01685                            Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections.  Assuming '@' notation for the collection %s.",
01686                                    curelem->GetName());
01687                            leafinfo = new TFormLeafInfo(cl,coll_offset,curelem);
01688                            useCollectionObject = kTRUE;
01689                         } else if (numberOfVarDim==1) {
01690                            R__ASSERT(maininfo);
01691                            leafinfo =
01692                               new TFormLeafInfoMultiVarDimCollection(cl,coll_offset,
01693                                                                      curelem,maininfo);
01694                            fHasMultipleVarDim[code] = kTRUE;
01695                            leafinfo->fNext = new TFormLeafInfoCollection(cl,coll_offset,curelem);
01696                            numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
01697                         } else {
01698                            leafinfo = new TFormLeafInfoCollection(cl,coll_offset,curelem);
01699                            numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
01700                         }
01701                         if (maininfo==0) maininfo = leafinfo;
01702                         if (previnfo==0) previnfo = leafinfo;
01703                         else {
01704                            previnfo->fNext = leafinfo;
01705                            previnfo = leafinfo;
01706                         }
01707                         if (leafinfo->fNext) {
01708                            previnfo = leafinfo->fNext;
01709                         }
01710                         leafinfo = 0;
01711                         cl = sub_cl;
01712                         break;
01713                      }
01714                   }
01715                }
01716 
01717             }
01718 
01719             if (element) {
01720                Int_t type = element->GetNewType();
01721                if (type<60 && type!=0) {
01722                   // This is a basic type ...
01723                   if (numberOfVarDim>=1 && type>40) {
01724                      // We have a variable array within a variable array!
01725                      leafinfo = new TFormLeafInfoMultiVarDim(cl,offset,element,maininfo);
01726                      fHasMultipleVarDim[code] = kTRUE;
01727                   } else {
01728                      if (leafinfo && type<=40 ) {
01729                         leafinfo->AddOffset(offset,element);
01730                      } else {
01731                         leafinfo = new TFormLeafInfo(cl,offset,element);
01732                      }
01733                   }
01734                } else {
01735                   Bool_t object = kFALSE;
01736                   Bool_t pointer = kFALSE;
01737                   Bool_t objarr = kFALSE;
01738                   switch(type) {
01739                      case TStreamerInfo::kObjectp:
01740                      case TStreamerInfo::kObjectP:
01741                      case TStreamerInfo::kSTLp:
01742                      case TStreamerInfo::kAnyp:
01743                      case TStreamerInfo::kAnyP:
01744                      case TStreamerInfo::kOffsetL + TStreamerInfo::kObjectP:
01745                      case TStreamerInfo::kOffsetL + TStreamerInfo::kSTLp:
01746                      case TStreamerInfo::kOffsetL + TStreamerInfo::kAnyp:
01747                      case TStreamerInfo::kOffsetL + TStreamerInfo::kObjectp:
01748                      case TStreamerInfo::kOffsetL + TStreamerInfo::kAnyP:
01749                         pointer = kTRUE;
01750                         break;
01751                      case TStreamerInfo::kBase:
01752                      case TStreamerInfo::kAny :
01753                      case TStreamerInfo::kSTL:
01754                      case TStreamerInfo::kObject:
01755                      case TStreamerInfo::kTString:
01756                      case TStreamerInfo::kTNamed:
01757                      case TStreamerInfo::kTObject:
01758                         object = kTRUE;
01759                         break;
01760                      case TStreamerInfo::kOffsetL + TStreamerInfo::kAny:
01761                      case TStreamerInfo::kOffsetL + TStreamerInfo::kSTL:
01762                      case TStreamerInfo::kOffsetL + TStreamerInfo::kObject:
01763                         objarr = kTRUE;
01764                         break;
01765                      case TStreamerInfo::kStreamer:
01766                      case TStreamerInfo::kStreamLoop:
01767                         // Unsupported case.
01768                         Error("DefinedVariable",
01769                               "%s is a datamember of %s BUT is not yet of a supported type (%d)",
01770                               right,cl ? cl->GetName() : "unknown class",type);
01771                         return -2;
01772                      default:
01773                         // Unknown and Unsupported case.
01774                         Error("DefinedVariable",
01775                               "%s is a datamember of %s BUT is not of a unknown type (%d)",
01776                               right,cl ? cl->GetName() : "unknown class",type);
01777                         return -2;
01778                   }
01779 
01780                   if (object && !useCollectionObject &&
01781                       ( element->GetClassPointer() ==  TClonesArray::Class()
01782                         || element->GetClassPointer()->GetCollectionProxy() ) )
01783                   {
01784                      object = kFALSE;
01785                   }
01786                   if (object && leafinfo) {
01787                      leafinfo->AddOffset(offset,element);
01788                   } else if (objarr) {
01789                      // This is an embedded array of objects. We can not increase the offset.
01790                      leafinfo = new TFormLeafInfo(cl,offset,element);
01791                      mustderef = kTRUE;
01792                   } else {
01793 
01794                      if (!useCollectionObject && element->GetClassPointer() ==  TClonesArray::Class()) {
01795 
01796                         leafinfo = new TFormLeafInfoClones(cl,offset,element);
01797                         mustderef = kTRUE;
01798 
01799                      } else if (!useCollectionObject &&  element->GetClassPointer()
01800                                 && element->GetClassPointer()->GetCollectionProxy()) {
01801 
01802                         mustderef = kTRUE;
01803                         if (numberOfVarDim>1) {
01804                            Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections.  Assuming '@' notation for the collection %s.",
01805                                    element->GetName());
01806                            leafinfo = new TFormLeafInfo(cl,offset,element);
01807                            useCollectionObject = kTRUE;
01808                         } else if (numberOfVarDim==1) {
01809                            R__ASSERT(maininfo);
01810                            leafinfo =
01811                               new TFormLeafInfoMultiVarDimCollection(cl,offset,element,maininfo);
01812 
01813                            fHasMultipleVarDim[code] = kTRUE;
01814                            //numberOfVarDim += RegisterDimensions(code,leafinfo);
01815                            //cl = cl->GetCollectionProxy()->GetValueClass();
01816 
01817                            //if (maininfo==0) maininfo = leafinfo;
01818                            //if (previnfo==0) previnfo = leafinfo;
01819                            //else {
01820                            //   previnfo->fNext = leafinfo;
01821                            //   previnfo = leafinfo;
01822                            //}
01823                            leafinfo->fNext =  new TFormLeafInfoCollection(cl, offset, element);
01824                            if (element->GetClassPointer()->GetCollectionProxy()->GetValueClass()==0) {
01825                               TFormLeafInfo *info = new TFormLeafInfoNumerical(
01826                                  element->GetClassPointer()->GetCollectionProxy());
01827                               if (leafinfo->fNext) leafinfo->fNext->fNext = info;
01828                               else leafinfo->fNext = info;
01829                            }
01830                         } else {
01831                            leafinfo =  new TFormLeafInfoCollection(cl, offset, element);
01832 
01833                            TClass *elemCl = element->GetClassPointer();
01834                            TClass *valueCl = elemCl->GetCollectionProxy()->GetValueClass();
01835                            if (!maininfo) maininfo = leafinfo;
01836 
01837                            if (valueCl!=0 && valueCl->GetCollectionProxy()!=0) {
01838 
01839                               numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,kFALSE);
01840                               if (previnfo==0) previnfo = leafinfo;
01841                               else {
01842                                  previnfo->fNext = leafinfo;
01843                                  previnfo = leafinfo;
01844                               }
01845                               leafinfo = new TFormLeafInfoMultiVarDimCollection(elemCl,0,
01846                                  elemCl->GetCollectionProxy()->GetValueClass(),maininfo);
01847                               //numberOfVarDim += RegisterDimensions(code,previnfo->fNext);
01848                               fHasMultipleVarDim[code] = kTRUE;
01849                               //previnfo = previnfo->fNext;
01850                               leafinfo->fNext =  new TFormLeafInfoCollection(elemCl,0,
01851                                  valueCl);
01852                               elemCl = valueCl;
01853                            }
01854                            if (elemCl->GetCollectionProxy() &&
01855                                elemCl->GetCollectionProxy()->GetValueClass()==0) {
01856                               TFormLeafInfo *info = new TFormLeafInfoNumerical(elemCl->GetCollectionProxy());
01857                               if (leafinfo->fNext) leafinfo->fNext->fNext = info;
01858                               else leafinfo->fNext = info;
01859                            }
01860                         }
01861                      } else if ( (object || pointer) && !useReferenceObject && element->GetClassPointer()->GetReferenceProxy() ) {
01862                         TClass* c = element->GetClassPointer();
01863                         R__LoadBranch(leaf->GetBranch(),readentry,fQuickLoad);
01864                         if ( object )  {
01865                            leafinfo = new TFormLeafInfoReference(c, element, offset);
01866                         }
01867                         else  {
01868                            leafinfo = new TFormLeafInfoPointer(cl,offset,element);
01869                            leafinfo->fNext = new TFormLeafInfoReference(c, element, 0);
01870                         }
01871                         //if ( c->GetReferenceProxy()->HasCounter() )  {
01872                         //   numberOfVarDim += RegisterDimensions(code,-1);
01873                         //}
01874                         prevUseReferenceObject = kFALSE;
01875                         needClass = kFALSE;
01876                         mustderef = kTRUE;
01877                      } else if (pointer) {
01878                         // this is a pointer to be followed.
01879                         leafinfo = new TFormLeafInfoPointer(cl,offset,element);
01880                         mustderef = kTRUE;
01881                      } else {
01882                         // this is an embedded object.
01883                         R__ASSERT(object);
01884                         leafinfo = new TFormLeafInfo(cl,offset,element);
01885                      }
01886                   }
01887                }
01888             } else {
01889                if (cl) Error("DefinedVariable","%s is not a datamember of %s",work,cl->GetName());
01890                // no else, we warned earlier that the class was missing.
01891                return -1;
01892             }
01893 
01894             numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,useCollectionObject); // Note or useCollectionObject||prevUseColectionObject
01895             if (maininfo==0) {
01896                maininfo = leafinfo;
01897             }
01898             if (previnfo==0) {
01899                previnfo = leafinfo;
01900             } else if (previnfo!=leafinfo) {
01901                previnfo->fNext = leafinfo;
01902                previnfo = leafinfo;
01903             }
01904             while (previnfo->fNext) previnfo = previnfo->fNext;
01905 
01906             if ( right[i] != '\0' )  {
01907                if ( !needClass && mustderef )   {
01908                   maininfo->SetBranch(leaf->GetBranch());
01909                   char *ptr = (char*)maininfo->GetValuePointer(leaf,0);
01910                   TFormLeafInfoReference* refInfo = 0;
01911                   if ( !maininfo->IsReference() )  {
01912                      for( TFormLeafInfo* inf = maininfo->fNext; inf; inf = inf->fNext )  {
01913                         if ( inf->IsReference() )  {
01914                            refInfo = (TFormLeafInfoReference*)inf;
01915                         }
01916                      }
01917                   }
01918                   else {
01919                      refInfo = (TFormLeafInfoReference*)maininfo;
01920                   }
01921                   if ( refInfo )  {
01922                      cl = refInfo->GetValueClass(ptr);
01923                      if ( !cl )  {
01924                         Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
01925                         return -1;
01926                      }
01927                      element = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(work,offset);
01928                   }
01929                   else  {
01930                      Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
01931                      return -1;
01932                   }
01933                }
01934                else if ( needClass )  {
01935                   cl = element->GetClassPointer();
01936                }
01937             }
01938             if (mustderef) leafinfo = 0;
01939             current = &(work[0]);
01940             *current = 0;
01941 
01942             R__ASSERT(right[i] != '[');  // We are supposed to have removed all dimensions already!
01943 
01944          } else
01945             *current++ = right[i];
01946       }
01947       if (maininfo) {
01948          fDataMembers.AddAtAndExpand(maininfo,code);
01949          if (leaf) fLookupType[code] = kDataMember;
01950          else fLookupType[code] = kTreeMember;
01951       }
01952    }
01953 
01954    if (strlen(work)!=0) {
01955       // We have something left to analyze.  Let's make this an error case!
01956       return -1;
01957    }
01958 
01959    TClass *objClass = EvalClass(code);
01960    if (objClass && !useLeafCollectionObject && objClass->GetCollectionProxy() && objClass->GetCollectionProxy()->GetValueClass()) {
01961       TFormLeafInfo *last = 0;
01962       if ( SwitchToFormLeafInfo(code) ) {
01963          
01964          last = (TFormLeafInfo*)fDataMembers.At(code);
01965          
01966          if (!last) return action;
01967          while (last->fNext) { last = last->fNext; }
01968          
01969       }
01970       if (last && last->GetClass() != objClass) {
01971          TClass *mother_cl;
01972          if (leaf->IsA()==TLeafObject::Class()) {
01973             // in this case mother_cl is not really used
01974             mother_cl = cl;
01975          } else {
01976             mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
01977          }
01978          
01979          TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(mother_cl, 0, objClass, kFALSE);
01980          // The dimension needs to be handled!
01981          numberOfVarDim += RegisterDimensions(code,collectioninfo,maininfo,kFALSE);
01982          last->fNext = collectioninfo;
01983       }
01984       numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0
01985       objClass = objClass->GetCollectionProxy()->GetValueClass();
01986    }
01987    if (IsLeafString(code) || objClass == TString::Class() || objClass == stdStringClass) {
01988 
01989       TFormLeafInfo *last = 0;
01990       if ( SwitchToFormLeafInfo(code) ) {
01991 
01992          last = (TFormLeafInfo*)fDataMembers.At(code);
01993 
01994          if (!last) return action;
01995          while (last->fNext) { last = last->fNext; }
01996 
01997       }
01998       const char *funcname = 0;
01999       if (objClass == TString::Class()) {
02000          funcname = "Data";
02001          //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
02002       } else if (objClass == stdStringClass) {
02003          funcname = "c_str";
02004          //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
02005       }
02006       if (funcname) {
02007          TMethodCall *method = new TMethodCall(objClass, funcname, "");
02008          if (last) {
02009             last->fNext = new TFormLeafInfoMethod(objClass,method);
02010          } else {
02011             fDataMembers.AddAtAndExpand(new TFormLeafInfoMethod(objClass,method),code);
02012             if (leaf) fLookupType[code] = kDataMember;
02013             else fLookupType[code] = kTreeMember;
02014          }
02015       }
02016       return kDefinedString;
02017    }
02018 
02019    if (objClass) {
02020       TMethodCall *method = new TMethodCall(objClass, "AsDouble", "");
02021       if (method->IsValid()
02022           && (method->ReturnType() == TMethodCall::kLong || method->ReturnType() == TMethodCall::kDouble)) {
02023          
02024          TFormLeafInfo *last = 0;
02025          if (SwitchToFormLeafInfo(code)) {
02026             last = (TFormLeafInfo*)fDataMembers.At(code);
02027             // Improbable case
02028             if (!last) {
02029                delete method;
02030                return action;
02031             }
02032             while (last->fNext) { last = last->fNext; }
02033          }
02034          if (last) {
02035             last->fNext = new TFormLeafInfoMethod(objClass,method);
02036          } else {
02037             fDataMembers.AddAtAndExpand(new TFormLeafInfoMethod(objClass,method),code);
02038             if (leaf) fLookupType[code] = kDataMember;
02039             else fLookupType[code] = kTreeMember;
02040          }            
02041 
02042          return kDefinedVariable;
02043       }
02044       delete method;
02045       method = new TMethodCall(objClass, "AsString", "");
02046       if (method->IsValid()
02047           && method->ReturnType() == TMethodCall::kString) {
02048 
02049          TFormLeafInfo *last = 0;
02050          if (SwitchToFormLeafInfo(code)) {
02051             last = (TFormLeafInfo*)fDataMembers.At(code);
02052             // Improbable case
02053             if (!last) {
02054                delete method;
02055                return action;
02056             }
02057             while (last->fNext) { last = last->fNext; }
02058          }
02059          if (last) {
02060             last->fNext = new TFormLeafInfoMethod(objClass,method);
02061          } else {
02062             fDataMembers.AddAtAndExpand(new TFormLeafInfoMethod(objClass,method),code);
02063             if (leaf) fLookupType[code] = kDataMember;
02064             else fLookupType[code] = kTreeMember;
02065          }            
02066 
02067          //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
02068          return kDefinedString;
02069       }
02070       if (method->IsValid()
02071           && method->ReturnType() == TMethodCall::kOther) {
02072 
02073          TClass *rcl = 0;
02074          TFunction *f = method->GetMethod();
02075          if (f) rcl = TClass::GetClass(gInterpreter->TypeName(f->GetReturnTypeName()));
02076          if ((rcl == TString::Class() || rcl == stdStringClass) ) {
02077 
02078             TFormLeafInfo *last = 0;
02079             if (SwitchToFormLeafInfo(code)) {
02080                last = (TFormLeafInfo*)fDataMembers.At(code);
02081                // Improbable case
02082                if (!last) {
02083                   delete method;
02084                   return action;
02085                }
02086                while (last->fNext) { last = last->fNext; }
02087             }
02088             if (last) {
02089                last->fNext = new TFormLeafInfoMethod(objClass,method);
02090                last = last->fNext;
02091             } else {
02092                last = new TFormLeafInfoMethod(objClass,method);
02093                fDataMembers.AddAtAndExpand(last,code);
02094                if (leaf) fLookupType[code] = kDataMember;
02095                else fLookupType[code] = kTreeMember;
02096             }
02097 
02098             objClass = rcl;
02099 
02100             const char *funcname = 0;
02101             if (objClass == TString::Class()) {
02102                funcname = "Data";
02103             } else if (objClass == stdStringClass) {
02104                funcname = "c_str";
02105             }
02106             if (funcname) {
02107                method = new TMethodCall(objClass, funcname, "");
02108                last->fNext = new TFormLeafInfoMethod(objClass,method);
02109             }
02110             return kDefinedString;
02111          }
02112       }
02113       delete method;
02114    }
02115 
02116    return action;
02117 }
02118 //______________________________________________________________________________
02119 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)
02120 {
02121    // Look for the leaf corresponding to the start of expression.
02122    // It returns the corresponding leaf if any.
02123    // It also modify the following arguments:
02124    //   leftover: contain from expression that was not used to determine the leaf
02125    //   final:
02126    //   paran_level: number of un-matched open parenthesis
02127    //   cast_queue: list of cast to be done
02128    //   aliases: list of aliases used
02129    // Return <0 in case of failure
02130    // Return 0 if a leaf has been found
02131    // Return 2 if info about the TTree itself has been requested.
02132 
02133    // Later on we will need to read one entry, let's make sure
02134    // it is a real entry.
02135    if (fTree->GetTree()==0) {
02136       fTree->LoadTree(0);
02137       if (fTree->GetTree()==0) return -1;
02138    }
02139    Long64_t readentry = fTree->GetTree()->GetReadEntry();
02140    if (readentry==-1) readentry=0;
02141    const char *cname = expression;
02142    char    first[kMaxLen];  first[0] = '\0';
02143    char   second[kMaxLen]; second[0] = '\0';
02144    char    right[kMaxLen];  right[0] = '\0';
02145    char     work[kMaxLen];   work[0] = '\0';
02146    char     left[kMaxLen];   left[0] = '\0';
02147    char  scratch[kMaxLen];
02148    char scratch2[kMaxLen];
02149    std::string currentname;
02150    Int_t previousdot = 0;
02151    char *current;
02152    TLeaf *tmp_leaf=0;
02153    TBranch *branch=0, *tmp_branch=0;
02154    Int_t nchname = strlen(cname);
02155    Int_t i;
02156    Bool_t foundAtSign = kFALSE;
02157 
02158    for (i=0, current = &(work[0]); i<=nchname && !final;i++ ) {
02159       // We will treated the terminator as a token.
02160       *current++ = cname[i];
02161 
02162       if (cname[i] == '(') {
02163          ++paran_level;
02164 
02165          if (current==work+1) {
02166             // If the expression starts with a paranthesis, we are likely
02167             // to have a cast operator inside.
02168             current--;
02169          }
02170          continue;
02171          //i++;
02172          //while( cname[i]!=')' && cname[i] ) {
02173          //   *current++ = cname[i++];
02174          //}
02175          //*current++ = cname[i];
02176          ////*current = 0;
02177          //continue;
02178       }
02179       if (cname[i] == ')') {
02180          if (paran_level==0) {
02181             Error("DefinedVariable","Unmatched paranthesis in %s",fullExpression);
02182             return -1;
02183          }
02184          // Let's see if work is a classname.
02185          *(--current) = 0;
02186          paran_level--;
02187          TString cast_name = gInterpreter->TypeName(work);
02188          TClass *cast_cl = TClass::GetClass(cast_name);
02189          if (cast_cl) {
02190             // We must have a cast
02191             castqueue.AddAtAndExpand(cast_cl,paran_level);
02192             current = &(work[0]);
02193             *current = 0;
02194             //            Warning("DefinedVariable","Found cast to %s",cast_fullExpression);
02195             continue;
02196          } else if (gROOT->GetType(cast_name)) {
02197             // We reset work
02198             current = &(work[0]);
02199             *current = 0;
02200             Warning("DefinedVariable",
02201                "Casting to primary types like \"%s\" is not supported yet",cast_name.Data());
02202             continue;
02203          }
02204 
02205          *(current++)=')';
02206          *current='\0';
02207          char *params = strchr(work,'(');
02208          if (params) {
02209             *params = 0; params++;
02210 
02211             if (branch && !leaf) {
02212                // We have a branch but not a leaf.  We are likely to have found
02213                // the top of split branch.
02214                if (BranchHasMethod(0, branch, work, params, readentry)) {
02215                   //fprintf(stderr, "Does have a method %s for %s.\n", work, branch->GetName());
02216                }
02217             }
02218 
02219             // What we have so far might be a member function of one of the
02220             // leaves that are not splitted (for example "GetNtrack" for the Event class).
02221             TIter next(fTree->GetIteratorOnAllLeaves());
02222             TLeaf* leafcur = 0;
02223             while (!leaf && (leafcur = (TLeaf*) next())) {
02224                TBranch* br = leafcur->GetBranch();
02225                Bool_t yes = BranchHasMethod(leafcur, br, work, params, readentry);
02226                if (yes) {
02227                   leaf = leafcur;
02228                   //fprintf(stderr, "Does have a method %s for %s found in leafcur %s.\n", work, leafcur->GetBranch()->GetName(), leafcur->GetName());
02229                }
02230             }
02231             if (!leaf) {
02232                // Check for an alias.
02233                if (strlen(left) && left[strlen(left)-1]=='.') left[strlen(left)-1]=0;
02234                const char *aliasValue = fTree->GetAlias(left);
02235                if (aliasValue && strcspn(aliasValue,"+*/-%&!=<>|")==strlen(aliasValue)) {
02236                   // First check whether we are using this alias recursively (this would
02237                   // lead to an infinite recursion.
02238                   if (find(aliasUsed.begin(),
02239                      aliasUsed.end(),
02240                      left) != aliasUsed.end()) {
02241                         Error("DefinedVariable",
02242                            "The substitution of the branch alias \"%s\" by \"%s\" in \"%s\" failed\n"\
02243                            "\tbecause \"%s\" is used [recursively] in its own definition!",
02244                            left,aliasValue,fullExpression,left);
02245                         return -3;
02246                   }
02247                   aliasUsed.push_back(left);
02248                   TString newExpression = aliasValue;
02249                   newExpression += (cname+strlen(left));
02250                   Int_t res = FindLeafForExpression(newExpression, leaf, leftover, final, paran_level,
02251                      castqueue, aliasUsed, useLeafCollectionObject, fullExpression);
02252                   if (res<0) {
02253                      Error("DefinedVariable",
02254                         "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue);
02255                      return -3;
02256                   }
02257                   return res;
02258                }
02259 
02260                // This is actually not really any error, we probably received something
02261                // like "abs(some_val)", let TFormula decompose it first.
02262                return -1;
02263             }
02264             //         if (!leaf->InheritsFrom(TLeafObject::Class()) ) {
02265             // If the leaf that we found so far is not a TLeafObject then there is
02266             // nothing we would be able to do.
02267             //   Error("DefinedVariable","Need a TLeafObject to call a function!");
02268             // return -1;
02269             //}
02270             // We need to recover the info not used.
02271             strlcpy(right,work,kMaxLen);
02272             strncat(right,"(",kMaxLen-1-strlen(right));
02273             strncat(right,params,kMaxLen-1-strlen(right));
02274             final = kTRUE;
02275 
02276             // we reset work
02277             current = &(work[0]);
02278             *current = 0;
02279             break;
02280          }
02281       }
02282       if (cname[i] == '.' || cname[i] == '\0' || cname[i] == ')') {
02283          // A delimiter happened let's see if what we have seen
02284          // so far does point to a leaf.
02285          *current = '\0';
02286 
02287          Int_t len = strlen(work);
02288          if (work[0]=='@') {
02289             foundAtSign = kTRUE;
02290             Int_t l = 0;
02291             for(l=0;work[l+1]!=0;++l) work[l] = work[l+1];
02292             work[l] = '\0';
02293             --current;
02294          } else if (len>=2 && work[len-2]=='@') {
02295             foundAtSign = kTRUE;
02296             work[len-2] = cname[i];
02297             work[len-1] = '\0';
02298             --current;
02299          } else {
02300             foundAtSign = kFALSE;
02301          }
02302 
02303          if (left[0]==0) strlcpy(left,work,kMaxLen);
02304          if (!leaf && !branch) {
02305             // So far, we have not found a matching leaf or branch.
02306             strlcpy(first,work,kMaxLen);
02307 
02308             std::string treename(first);
02309             if (treename.size() && treename[treename.size()-1]=='.') {
02310                treename.erase(treename.size()-1);
02311             }
02312             if (treename== "This" /* || treename == fTree->GetName() */ ) {
02313                // Request info about the TTree object itself,
02314                TNamed *named = new TNamed(fTree->GetName(),fTree->GetName());
02315                fLeafNames.AddAtAndExpand(named,fNcodes);
02316                fLeaves.AddAtAndExpand(fTree,fNcodes);
02317                if (cname[i]) leftover = &(cname[i+1]);
02318                return 2;
02319             }
02320             // The following would allow to access the friend by name
02321             // however, it would also prevent the access of the leaves
02322             // within the friend.  We could use the '@' notation here
02323             // however this would not be aesthetically pleasing :(
02324             // What we need to do, is add the ability to look ahead to
02325             // the next 'token' to decide whether we to access the tree
02326             // or its leaf.
02327             //} else {
02328             //   TTree *tfriend = fTree->GetFriend(treename.c_str());
02329             //   TTree *realtree = fTree->GetTree();
02330             //   if (!tfriend && realtree != fTree){
02331             //      // If it is a chain and we did not find a friend,
02332             //      // let's try with the internal tree.
02333             //      tfriend = realtree->GetFriend(treename.c_str());
02334             //   }
02335             //   if (tfriend) {
02336             //      TNamed *named = new TNamed(treename.c_str(),tfriend->GetName());
02337             //      fLeafNames.AddAtAndExpand(named,fNcodes);
02338             //      fLeaves.AddAtAndExpand(tfriend,fNcodes);
02339             //      if (cname[i]) leftover = &(cname[i+1]);
02340             //      return 2;
02341             //   }
02342             //}
02343 
02344             branch = fTree->FindBranch(first);
02345             leaf = fTree->FindLeaf(first);
02346 
02347             // Now look with the delimiter removed (we looked with it first
02348             // because a dot is allowed at the end of some branches).
02349             if (cname[i]) first[strlen(first)-1]='\0';
02350             if (!branch) branch = fTree->FindBranch(first);
02351             if (!leaf) leaf = fTree->FindLeaf(first);
02352             TClass* cl = 0;
02353             if ( branch && branch->InheritsFrom(TBranchElement::Class()) ) {
02354                int offset=0;
02355                TBranchElement* bElt = (TBranchElement*)branch;
02356                TStreamerInfo* info  = bElt->GetInfo();
02357                TStreamerElement* element = info ? info->GetStreamerElement(first,offset) : 0;
02358                if (element) cl = element->GetClassPointer();
02359                if ( cl && !cl->GetReferenceProxy() ) cl = 0;
02360             }
02361             if ( cl )  {  // We have a reference class here....
02362                final = kTRUE;
02363                useLeafCollectionObject = foundAtSign;
02364                // we reset work
02365                current = &(work[0]);
02366                *current = 0;
02367             }
02368             else if (branch && (foundAtSign || cname[i] != 0)  ) {
02369                // Since we found a branch and there is more information in the name,
02370                // we do NOT look at the 'IsOnTerminalBranch' status of the leaf
02371                // we found ... yet!
02372 
02373                if (leaf==0) {
02374                   // Note we do not know (yet?) what (if anything) to do
02375                   // for a TBranchObject branch.
02376                   if (branch->InheritsFrom(TBranchElement::Class()) ) {
02377                      Int_t type = ((TBranchElement*)branch)->GetType();
02378                      if ( type == 3 || type ==4) {
02379                         // We have a Collection branch.
02380                         leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
02381                         if (foundAtSign) {
02382                            useLeafCollectionObject = foundAtSign;
02383                            foundAtSign = kFALSE;
02384                            current = &(work[0]);
02385                            *current = 0;
02386                            ++i;
02387                            break;
02388                         }
02389                      }
02390                   }
02391                }
02392 
02393                // we reset work
02394                useLeafCollectionObject = foundAtSign;
02395                foundAtSign = kFALSE;
02396                current = &(work[0]);
02397                *current = 0;
02398             } else if (leaf || branch) {
02399                if (leaf && branch) {
02400                   // We found both a leaf and branch matching the request name
02401                   // let's see which one is the proper one to use! (On annoying case
02402                   // is that where the same name is repeated ( varname.varname )
02403 
02404                   // We always give priority to the branch
02405                   // leaf = 0;
02406                }
02407                if (leaf && leaf->IsOnTerminalBranch()) {
02408                   // This is a non-object leaf, it should NOT be specified more except for
02409                   // dimensions.
02410                   final = kTRUE;
02411                }
02412                // we reset work
02413                current = &(work[0]);
02414                *current = 0;
02415             } else {
02416                // What we have so far might be a data member of one of the
02417                // leaves that are not splitted (for example "fNtrack" for the Event class.
02418                TLeaf *leafcur = GetLeafWithDatamember(first,work,readentry);
02419                if (leafcur) {
02420                   leaf = leafcur;
02421                   branch = leaf->GetBranch();
02422                   if (leaf->IsOnTerminalBranch()) {
02423                      final = kTRUE;
02424                      strlcpy(right,first,kMaxLen);
02425                      //We need to put the delimiter back!
02426                      if (foundAtSign) strncat(right,"@",kMaxLen-1-strlen(right));
02427                      if (cname[i]=='.') strncat(right,".",kMaxLen-1-strlen(right));
02428 
02429                      // We reset work
02430                      current = &(work[0]);
02431                      *current = 0;
02432                   };
02433                } else if (cname[i] == '.') {
02434                   // If we have a branch that match a name preceded by a dot
02435                   // then we assume we are trying to drill down the branch
02436                   // Let look if one of the top level branch has a branch with the name
02437                   // we are looking for.
02438                   TBranch *branchcur;
02439                   TIter next( fTree->GetListOfBranches() );
02440                   while(!branch && (branchcur=(TBranch*)next()) ) {
02441                      branch = branchcur->FindBranch(first);
02442                   }
02443                   if (branch) {
02444                      // We reset work
02445                      current = &(work[0]);
02446                      *current = 0;
02447                   }
02448                }
02449             }
02450          } else {  // correspond to if (leaf || branch)
02451             if (final) {
02452                Error("DefinedVariable", "Unexpected control flow!");
02453                return -1;
02454             }
02455 
02456             // No dot is allowed in subbranches and leaves, so
02457             // we always remove it in the present case.
02458             if (cname[i]) work[strlen(work)-1] = '\0';
02459             snprintf(scratch,sizeof(scratch),"%s.%s",first,work);
02460             snprintf(scratch2,sizeof(scratch2),"%s.%s.%s",first,second,work);
02461 
02462             if (previousdot) {
02463                currentname = &(work[previousdot+1]);
02464             }
02465 
02466             // First look for the current 'word' in the list of
02467             // leaf of the
02468             if (branch) {
02469                tmp_leaf = branch->FindLeaf(work);
02470                if (!tmp_leaf)  tmp_leaf = branch->FindLeaf(scratch);
02471                if (!tmp_leaf)  tmp_leaf = branch->FindLeaf(scratch2);
02472                if (!tmp_leaf)  tmp_leaf = branch->FindLeaf(currentname.c_str());
02473             }
02474             if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
02475                // This is a non-object leaf, it should NOT be specified more except for
02476                // dimensions.
02477                final = kTRUE;
02478             }
02479 
02480             if (branch) {
02481                tmp_branch = branch->FindBranch(work);
02482                if (!tmp_branch) tmp_branch = branch->FindBranch(scratch);
02483                if (!tmp_branch) tmp_branch = branch->FindBranch(scratch2);
02484                if (!tmp_branch) tmp_branch = branch->FindBranch(currentname.c_str());
02485             }
02486             if (tmp_branch) {
02487                branch=tmp_branch;
02488 
02489                // NOTE: Should we look for a leaf within here?
02490                if (!final) {
02491                   tmp_leaf = branch->FindLeaf(work);
02492                   if (!tmp_leaf)  tmp_leaf = branch->FindLeaf(scratch);
02493                   if (!tmp_leaf)  tmp_leaf = branch->FindLeaf(scratch2);
02494                   if (!tmp_leaf)  tmp_leaf = branch->FindLeaf(currentname.c_str());
02495                   if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
02496                      // This is a non-object leaf, it should NOT be specified
02497                      // more except for dimensions.
02498                      final = kTRUE;
02499                      leaf = tmp_leaf;
02500                   }
02501                }
02502             }
02503             if (tmp_leaf) {
02504                // Something was found.
02505                if (second[0]) strncat(second,".",kMaxLen-1-strlen(second));
02506                strncat(second,work,kMaxLen-1-strlen(second));
02507                leaf = tmp_leaf;
02508                useLeafCollectionObject = foundAtSign;
02509                foundAtSign = kFALSE;
02510 
02511                // we reset work
02512                current = &(work[0]);
02513                *current = 0;
02514             } else {
02515                //We need to put the delimiter back!
02516                if (strlen(work)) {
02517                   if (foundAtSign) {
02518                      Int_t where = strlen(work);
02519                      work[where] = '@';
02520                      work[where+1] = cname[i];
02521                      ++current;
02522                      previousdot = where+1;
02523                   } else {
02524                      previousdot = strlen(work);
02525                      work[strlen(work)] = cname[i];
02526                   }
02527                } else --current;
02528             }
02529          }
02530       }
02531    }
02532 
02533    // Copy the left over for later use.
02534    if (strlen(work)) {
02535       strncat(right,work,kMaxLen-1-strlen(right));
02536    }
02537 
02538    if (i<nchname) {
02539       if (strlen(right) && right[strlen(right)-1]!='.' && cname[i]!='.') {
02540          // In some cases we remove a little to fast the period, we add
02541          // it back if we need.  It is assumed that 'right' and the rest of
02542          // the name was cut by a delimiter, so this should be safe.
02543          strncat(right,".",kMaxLen-1-strlen(right));
02544       }
02545       strncat(right,&cname[i],kMaxLen-1-strlen(right));
02546    }
02547 
02548    if (!final && branch) {
02549       if (!leaf) {
02550          leaf = (TLeaf*)branch->GetListOfLeaves()->UncheckedAt(0);
02551          if (!leaf) return -1;
02552       }
02553       final = leaf->IsOnTerminalBranch();
02554    }
02555 
02556    if (leaf && leaf->InheritsFrom(TLeafObject::Class()) ) {
02557       if (strlen(right)==0) strlcpy(right,work,kMaxLen);
02558    }
02559 
02560    if (leaf==0 && left[0]!=0) {
02561       if (left[strlen(left)-1]=='.') left[strlen(left)-1]=0;
02562 
02563       // Check for an alias.
02564       const char *aliasValue = fTree->GetAlias(left);
02565       if (aliasValue && strcspn(aliasValue,"[]+*/-%&!=<>|")==strlen(aliasValue)) {
02566          // First check whether we are using this alias recursively (this would
02567          // lead to an infinite recursion).
02568          if (find(aliasUsed.begin(),
02569                   aliasUsed.end(),
02570                   left) != aliasUsed.end()) {
02571             Error("DefinedVariable",
02572                   "The substitution of the branch alias \"%s\" by \"%s\" in \"%s\" failed\n"\
02573                   "\tbecause \"%s\" is used [recursively] in its own definition!",
02574                   left,aliasValue,fullExpression,left);
02575             return -3;
02576          }
02577          aliasUsed.push_back(left);
02578          TString newExpression = aliasValue;
02579          newExpression += (cname+strlen(left));
02580          Int_t res = FindLeafForExpression(newExpression, leaf, leftover, final, paran_level,
02581                                            castqueue, aliasUsed, useLeafCollectionObject, fullExpression);
02582          if (res<0) {
02583             Error("DefinedVariable",
02584                   "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue);
02585             return -3;
02586          }
02587          return res;
02588       }
02589    }
02590    leftover = right;
02591 
02592    return 0;
02593 }
02594 
02595 //______________________________________________________________________________
02596 Int_t TTreeFormula::DefinedVariable(TString &name, Int_t &action)
02597 {
02598 //*-*-*-*-*-*Check if name is in the list of Tree/Branch leaves*-*-*-*-*
02599 //*-*        ==================================================
02600 //
02601 //   This member function redefines the function in TFormula
02602 //   If a leaf has a name corresponding to the argument name, then
02603 //   returns a new code.
02604 //   A TTreeFormula may contain more than one variable.
02605 //   For each variable referenced, the pointers to the corresponding
02606 //   branch and leaf is stored in the object arrays fBranches and fLeaves.
02607 //
02608 //   name can be :
02609 //      - Leaf_Name (simple variable or data member of a ClonesArray)
02610 //      - Branch_Name.Leaf_Name
02611 //      - Branch_Name.Method_Name
02612 //      - Leaf_Name[index]
02613 //      - Branch_Name.Leaf_Name[index]
02614 //      - Branch_Name.Leaf_Name[index1]
02615 //      - Branch_Name.Leaf_Name[][index2]
02616 //      - Branch_Name.Leaf_Name[index1][index2]
02617 //   New additions:
02618 //      - Branch_Name.Leaf_Name[OtherLeaf_Name]
02619 //      - Branch_Name.Datamember_Name
02620 //      - '.' can be replaced by '->'
02621 //   and
02622 //      - Branch_Name[index1].Leaf_Name[index2]
02623 //      - Leaf_name[index].Action().OtherAction(param)
02624 //      - Leaf_name[index].Action()[val].OtherAction(param)
02625 //
02626 //   The expected returns values are
02627 //     -2 :  the name has been recognized but won't be usable
02628 //     -1 :  the name has not been recognized
02629 //    >=0 :  the name has been recognized, return the internal code for this name.
02630 //
02631 
02632 
02633    action = kDefinedVariable;
02634    if (!fTree) return -1;
02635 
02636    fNpar = 0;
02637    if (name.Length() > kMaxLen) return -1;
02638    Int_t i,k;
02639 
02640    if (name == "Entry$") {
02641       Int_t code = fNcodes++;
02642       fCodes[code] = 0;
02643       fLookupType[code] = kIndexOfEntry;
02644       return code;
02645    }
02646    if (name == "LocalEntry$") {
02647       Int_t code = fNcodes++;
02648       fCodes[code] = 0;
02649       fLookupType[code] = kIndexOfLocalEntry;
02650       return code;
02651    }
02652    if (name == "Entries$") {
02653       Int_t code = fNcodes++;
02654       fCodes[code] = 0;
02655       fLookupType[code] = kEntries;
02656       SetBit(kNeedEntries);
02657       fManager->SetBit(kNeedEntries);
02658       return code;
02659    }
02660    if (name == "Iteration$") {
02661       Int_t code = fNcodes++;
02662       fCodes[code] = 0;
02663       fLookupType[code] = kIteration;
02664       return code;
02665    }
02666    if (name == "Length$") {
02667       Int_t code = fNcodes++;
02668       fCodes[code] = 0;
02669       fLookupType[code] = kLength;
02670       return code;
02671    }
02672    static const char *lenfunc = "Length$(";
02673    if (strncmp(name.Data(),"Length$(",strlen(lenfunc))==0
02674        && name[name.Length()-1]==')') {
02675 
02676       TString subform = name.Data()+strlen(lenfunc);
02677       subform.Remove( subform.Length() - 1 );
02678       TTreeFormula *lengthForm = new TTreeFormula("lengthForm",subform,fTree);
02679       fAliases.AddAtAndExpand(lengthForm,fNoper);
02680       Int_t code = fNcodes++;
02681       fCodes[code] = 0;
02682       fLookupType[code] = kLengthFunc;
02683       return code;
02684    }
02685    static const char *minfunc = "Min$(";
02686    if (strncmp(name.Data(),"Min$(",strlen(minfunc))==0
02687        && name[name.Length()-1]==')') {
02688       
02689       TString subform = name.Data()+strlen(minfunc);
02690       subform.Remove( subform.Length() - 1 );
02691       TTreeFormula *minForm = new TTreeFormula("minForm",subform,fTree);
02692       fAliases.AddAtAndExpand(minForm,fNoper);
02693       Int_t code = fNcodes++;
02694       fCodes[code] = 0;
02695       fLookupType[code] = kMin;
02696       return code;
02697    }
02698    static const char *maxfunc = "Max$(";
02699    if (strncmp(name.Data(),"Max$(",strlen(maxfunc))==0
02700        && name[name.Length()-1]==')') {
02701       
02702       TString subform = name.Data()+strlen(maxfunc);
02703       subform.Remove( subform.Length() - 1 );
02704       TTreeFormula *maxForm = new TTreeFormula("maxForm",subform,fTree);
02705       fAliases.AddAtAndExpand(maxForm,fNoper);
02706       Int_t code = fNcodes++;
02707       fCodes[code] = 0;
02708       fLookupType[code] = kMax;
02709       return code;
02710    }
02711    static const char *sumfunc = "Sum$(";
02712    if (strncmp(name.Data(),"Sum$(",strlen(sumfunc))==0
02713        && name[name.Length()-1]==')') {
02714       
02715       TString subform = name.Data()+strlen(sumfunc);
02716       subform.Remove( subform.Length() - 1 );
02717       TTreeFormula *sumForm = new TTreeFormula("sumForm",subform,fTree);
02718       fAliases.AddAtAndExpand(sumForm,fNoper);
02719       Int_t code = fNcodes++;
02720       fCodes[code] = 0;
02721       fLookupType[code] = kSum;
02722       return code;
02723    }
02724    
02725    
02726    
02727    // Check for $Alt(expression1,expression2)
02728    Int_t res = DefineAlternate(name.Data());
02729    if (res!=0) {
02730       // There was either a syntax error or we found $Alt
02731       if (res<0) return res;
02732       action = res;
02733       return 0;
02734    }
02735 
02736    // Find the top level leaf and deal with dimensions
02737 
02738    char    cname[kMaxLen];  strlcpy(cname,name.Data(),kMaxLen);
02739    char     dims[kMaxLen];   dims[0] = '\0';
02740 
02741    Bool_t final = kFALSE;
02742 
02743    UInt_t paran_level = 0;
02744    TObjArray castqueue;
02745 
02746    // First, it is easier to remove all dimensions information from 'cname'
02747    Int_t cnamelen = strlen(cname);
02748    for(i=0,k=0; i<cnamelen; ++i, ++k) {
02749       if (cname[i] == '[') {
02750          int bracket = i;
02751          int bracket_level = 1;
02752          int j;
02753          for (j=++i; j<cnamelen && (bracket_level>0 || cname[j]=='['); j++, i++) {
02754             if (cname[j]=='[') bracket_level++;
02755             else if (cname[j]==']') bracket_level--;
02756          }
02757          if (bracket_level != 0) {
02758             //Error("DefinedVariable","Bracket unbalanced");
02759             return -1;
02760          }
02761          strncat(dims,&cname[bracket],j-bracket);
02762          //k += j-bracket;
02763       }
02764       if (i!=k) cname[k] = cname[i];
02765    }
02766    cname[k]='\0';
02767 
02768    Bool_t useLeafCollectionObject = kFALSE;
02769    TString leftover;
02770    TLeaf *leaf = 0;
02771    {
02772       std::vector<std::string> aliasSofar = fAliasesUsed;
02773       res = FindLeafForExpression(cname, leaf, leftover, final, paran_level, castqueue, aliasSofar, useLeafCollectionObject, name);
02774    }
02775    if (res<0) return res;
02776 
02777    if (!leaf && res!=2) {
02778       // Check for an alias.
02779       const char *aliasValue = fTree->GetAlias(cname);
02780       if (aliasValue) {
02781          // First check whether we are using this alias recursively (this would
02782          // lead to an infinite recursion.
02783          if (find(fAliasesUsed.begin(),
02784                   fAliasesUsed.end(),
02785                   cname) != fAliasesUsed.end()) {
02786             Error("DefinedVariable",
02787                   "The substitution of the alias \"%s\" by \"%s\" failed\n"\
02788                   "\tbecause \"%s\" is recursively used in its own definition!",
02789                   cname,aliasValue,cname);
02790             return -3;
02791          }
02792 
02793 
02794          if (strcspn(aliasValue,"+*/-%&!=<>|")!=strlen(aliasValue)) {
02795             // If the alias contains an operator, we need to use a nested formula
02796             // (since DefinedVariable must only add one entry to the operation's list).
02797             
02798             // Need to check the aliases used so far
02799             std::vector<std::string> aliasSofar = fAliasesUsed;
02800             aliasSofar.push_back( cname );
02801 
02802             TString subValue( aliasValue );
02803             if (dims[0]) {
02804                subValue += dims;
02805             }
02806 
02807             TTreeFormula *subform = new TTreeFormula(cname,subValue,fTree,aliasSofar); // Need to pass the aliases used so far.
02808 
02809             if (subform->GetNdim()==0) {
02810                delete subform;
02811                Error("DefinedVariable",
02812                      "The substitution of the alias \"%s\" by \"%s\" failed.",cname,aliasValue);
02813                return -3;
02814             }
02815 
02816             fManager->Add(subform);
02817             fAliases.AddAtAndExpand(subform,fNoper);
02818 
02819             if (subform->IsString()) {
02820                action = kAliasString;
02821                return 0;
02822             } else {
02823                action = kAlias;
02824                return 0;
02825             }
02826          } else { /* assumes strcspn(aliasValue,"[]")!=strlen(aliasValue) */
02827             TString thisAlias( aliasValue );
02828             thisAlias += dims;
02829             Int_t aliasRes = DefinedVariable(thisAlias,action);
02830             if (aliasRes<0) {
02831                // We failed but DefinedVariable has not printed why yet.
02832                // and because we want thoses to be printed _before_ the notice
02833                // of the failure of the substitution, we need to print them here.
02834                if (aliasRes==-1) {
02835                   Error("Compile", " Bad numerical expression : \"%s\"",thisAlias.Data()); 
02836                } else if (aliasRes==-2) {
02837                   Error("Compile", " Part of the Variable \"%s\" exists but some of it is not accessible or useable",thisAlias.Data()); 
02838                   
02839                }
02840                Error("DefinedVariable",
02841                      "The substitution of the alias \"%s\" by \"%s\" failed.",cname,aliasValue);
02842                return -3;               
02843             }
02844             return aliasRes;
02845          }
02846       }
02847    }
02848 
02849 
02850    if (leaf || res==2) {
02851 
02852       if (leaf && leaf->GetBranch() && leaf->GetBranch()->TestBit(kDoNotProcess)) {
02853          Error("DefinedVariable","the branch \"%s\" has to be enabled to be used",leaf->GetBranch()->GetName());
02854          return -2;
02855       }
02856 
02857       Int_t code = fNcodes++;
02858 
02859       // If needed will now parse the indexes specified for
02860       // arrays.
02861       if (dims[0]) {
02862          char *current = &( dims[0] );
02863          Int_t dim = 0;
02864          TString varindex;
02865          Int_t index;
02866          Int_t scanindex ;
02867          while (current) {
02868             current++;
02869             if (current[0] == ']') {
02870                fIndexes[code][dim] = -1; // Loop over all elements;
02871             } else {
02872                scanindex = sscanf(current,"%d",&index);
02873                if (scanindex) {
02874                   fIndexes[code][dim] = index;
02875                } else {
02876                   fIndexes[code][dim] = -2; // Index is calculated via a variable.
02877                   varindex = current;
02878                   char *end = (char*)(varindex.Data());
02879                   for(char bracket_level = 0;*end!=0;end++) {
02880                      if (*end=='[') bracket_level++;
02881                      if (bracket_level==0 && *end==']') break;
02882                      if (*end==']') bracket_level--;
02883                   }
02884                   *end = '\0';
02885                   fVarIndexes[code][dim] = new TTreeFormula("index_var",
02886                                                             varindex,
02887                                                             fTree);
02888                   current += strlen(varindex)+1; // move to the end of the index array
02889                }
02890             }
02891             dim ++;
02892             if (dim >= kMAXFORMDIM) {
02893                // NOTE: test that dim this is NOT too big!!
02894                break;
02895             }
02896             current = (char*)strstr( current, "[" );
02897          }
02898       }
02899 
02900       // Now that we have cleaned-up the expression, let's compare it to the content
02901       // of the leaf!
02902 
02903       res = ParseWithLeaf(leaf,leftover,final,paran_level,castqueue,useLeafCollectionObject,name);
02904       if (res<0) return res;
02905       if (res>0) action = res;
02906       return code;
02907    }
02908 
02909 //*-*- May be a graphical cut ?
02910    TCutG *gcut = (TCutG*)gROOT->GetListOfSpecials()->FindObject(name.Data());
02911    if (gcut) {
02912       if (gcut->GetObjectX()) {
02913          if(!gcut->GetObjectX()->InheritsFrom(TTreeFormula::Class())) {
02914             delete gcut->GetObjectX(); gcut->SetObjectX(0);
02915          }
02916       }
02917       if (gcut->GetObjectY()) {
02918          if(!gcut->GetObjectY()->InheritsFrom(TTreeFormula::Class())) {
02919             delete gcut->GetObjectY(); gcut->SetObjectY(0);
02920          }
02921       }
02922 
02923       Int_t code = fNcodes;
02924 
02925       if (strlen(gcut->GetVarX()) && strlen(gcut->GetVarY()) ) {
02926 
02927          TTreeFormula *fx = new TTreeFormula("f_x",gcut->GetVarX(),fTree);
02928          gcut->SetObjectX(fx);
02929 
02930          TTreeFormula *fy = new TTreeFormula("f_y",gcut->GetVarY(),fTree);
02931          gcut->SetObjectY(fy);
02932 
02933          fCodes[code] = -2;
02934 
02935       } else if (strlen(gcut->GetVarX())) {
02936 
02937          // Let's build the equivalent formula:
02938          // min(gcut->X) <= VarX <= max(gcut->Y)
02939          Double_t min = 0;
02940          Double_t max = 0;
02941          Int_t n = gcut->GetN();
02942          Double_t *x = gcut->GetX();
02943          min = max = x[0];
02944          for(Int_t i2 = 1; i2<n; i2++) {
02945             if (x[i2] < min) min = x[i2];
02946             if (x[i2] > max) max = x[i2];
02947          }
02948          TString formula = "(";
02949          formula += min;
02950          formula += "<=";
02951          formula += gcut->GetVarX();
02952          formula += " && ";
02953          formula += gcut->GetVarX();
02954          formula += "<=";
02955          formula += max;
02956          formula += ")";
02957 
02958          TTreeFormula *fx = new TTreeFormula("f_x",formula.Data(),fTree);
02959          gcut->SetObjectX(fx);
02960 
02961          fCodes[code] = -1;
02962 
02963       } else {
02964 
02965          Error("DefinedVariable","Found a TCutG without leaf information (%s)",
02966                gcut->GetName());
02967          return -1;
02968 
02969       }
02970 
02971       fExternalCuts.AddAtAndExpand(gcut,code);
02972       fNcodes++;
02973       fLookupType[code] = -1;
02974       return code;
02975    }
02976 
02977    //may be an entrylist
02978    TEntryList *elist = dynamic_cast<TEntryList*> (gDirectory->Get(name.Data()));
02979    if (elist) {
02980       Int_t code = fNcodes;
02981       fCodes[code] = 0;
02982       fExternalCuts.AddAtAndExpand(elist, code);
02983       fNcodes++;
02984       fLookupType[code] = kEntryList;
02985       return code;
02986 
02987    }
02988 
02989    return -1;
02990 }
02991 
02992 //______________________________________________________________________________
02993 TLeaf* TTreeFormula::GetLeafWithDatamember(const char* topchoice, const char* nextchoice, Long64_t readentry) const
02994 {
02995 
02996    // Return the leaf (if any) which contains an object containing
02997    // a data member which has the name provided in the arguments.
02998 
02999    TClass * cl = 0;
03000    TIter nextleaf (fTree->GetIteratorOnAllLeaves());
03001    TFormLeafInfo* clonesinfo = 0;
03002    TLeaf *leafcur;
03003    while ((leafcur = (TLeaf*)nextleaf())) {
03004       // The following code is used somewhere else, we need to factor it out.
03005 
03006       // Here since we are interested in data member, we want to consider only
03007       // 'terminal' branch and leaf.
03008       cl = 0;
03009       if (leafcur->InheritsFrom(TLeafObject::Class()) &&
03010           leafcur->GetBranch()->GetListOfBranches()->Last()==0) {
03011          TLeafObject *lobj = (TLeafObject*)leafcur;
03012          cl = lobj->GetClass();
03013       } else if (leafcur->InheritsFrom(TLeafElement::Class()) && leafcur->IsOnTerminalBranch()) {
03014          TLeafElement * lElem = (TLeafElement*) leafcur;
03015          if (lElem->IsOnTerminalBranch()) {
03016             TBranchElement *branchEl = (TBranchElement *)leafcur->GetBranch();
03017             Int_t type = branchEl->GetStreamerType();
03018             if (type==-1) {
03019                cl =  branchEl->GetInfo()->GetClass();
03020             } else if (type>60 || type==0) {
03021                // Case of an object data member.  Here we allow for the
03022                // variable name to be ommitted.  Eg, for Event.root with split
03023                // level 1 or above  Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
03024                TStreamerElement* element = (TStreamerElement*)
03025                   branchEl->GetInfo()->GetElems()[branchEl->GetID()];
03026                if (element) cl = element->GetClassPointer();
03027                else cl = 0;
03028             }
03029          }
03030 
03031       }
03032       if (clonesinfo) { delete clonesinfo; clonesinfo = 0; }
03033       if (cl ==  TClonesArray::Class()) {
03034          // We have a unsplit TClonesArray leaves
03035          // In this case we assume that cl is the class in which the TClonesArray
03036          // belongs.
03037          R__LoadBranch(leafcur->GetBranch(),readentry,fQuickLoad);
03038          TClonesArray * clones;
03039 
03040          TBranch *branch = leafcur->GetBranch();
03041          if  (   branch->IsA()==TBranchElement::Class()
03042                  && ((TBranchElement*)branch)->GetType()==31) {
03043 
03044             // We have an unsplit TClonesArray as part of a split TClonesArray!
03045 
03046             // Let's not dig any further.  If the user really wants a data member
03047             // inside the nested TClonesArray, it has to specify it explicitly.
03048 
03049             continue;
03050 
03051          } else {
03052             Bool_t toplevel = (branch == branch->GetMother());
03053             clonesinfo = new TFormLeafInfoClones(cl, 0, toplevel);
03054             clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leafcur,0);
03055          }
03056          if (clones) cl = clones->GetClass();
03057       } else if (cl && cl->GetCollectionProxy()) {
03058 
03059          // We have a unsplit Collection leaves
03060          // In this case we assume that cl is the class in which the TClonesArray
03061          // belongs.
03062 
03063          TBranch *branch = leafcur->GetBranch();
03064          if  (   branch->IsA()==TBranchElement::Class()
03065                  && ((TBranchElement*)branch)->GetType()==41) {
03066 
03067             // We have an unsplit Collection as part of a split Collection!
03068 
03069             // Let's not dig any further.  If the user really wants a data member
03070             // inside the nested Collection, it has to specify it explicitly.
03071 
03072             continue;
03073 
03074          } else {
03075             clonesinfo = new TFormLeafInfoCollection(cl, 0);
03076          }
03077          cl = cl->GetCollectionProxy()->GetValueClass();
03078       }
03079       if (cl) {
03080          // Now that we have the class, let's check if the topchoice is of its datamember
03081          // or if the nextchoice is a datamember of one of its datamember.
03082          Int_t offset;
03083          TStreamerInfo* info =  (TStreamerInfo*)cl->GetStreamerInfo();
03084          TStreamerElement* element = info?info->GetStreamerElement(topchoice,offset):0;
03085          if (!element) {
03086             TIter nextel( cl->GetStreamerInfo()->GetElements() );
03087             TStreamerElement * curelem;
03088             while ((curelem = (TStreamerElement*)nextel())) {
03089 
03090                if (curelem->GetClassPointer() ==  TClonesArray::Class()) {
03091                   // In case of a TClonesArray we need to load the data and read the
03092                   // clonesArray object before being able to look into the class inside.
03093                   // We need to do that because we are never interested in the TClonesArray
03094                   // itself but only in the object inside.
03095                   TBranch *branch = leafcur->GetBranch();
03096                   TFormLeafInfo *leafinfo = 0;
03097                   if (clonesinfo) {
03098                      leafinfo = clonesinfo;
03099                   } else if (branch->IsA()==TBranchElement::Class()
03100                              && ((TBranchElement*)branch)->GetType()==31) {
03101                      // Case of a sub branch of a TClonesArray
03102                      TBranchElement *branchEl = (TBranchElement*)branch;
03103                      TStreamerInfo *bel_info = branchEl->GetInfo();
03104                      TClass * mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
03105                      TStreamerElement *bel_element =
03106                         (TStreamerElement *)bel_info->GetElems()[branchEl->GetID()];
03107                      leafinfo = new TFormLeafInfoClones(mother_cl, 0, bel_element, kTRUE);
03108                   }
03109 
03110                   Int_t clones_offset;
03111                   ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),clones_offset);
03112                   TFormLeafInfo* sub_clonesinfo = new TFormLeafInfo(cl, clones_offset, curelem);
03113                   if (leafinfo)
03114                      if (leafinfo->fNext) leafinfo->fNext->fNext = sub_clonesinfo;
03115                      else leafinfo->fNext = sub_clonesinfo;
03116                   else leafinfo = sub_clonesinfo;
03117 
03118                   R__LoadBranch(branch,readentry,fQuickLoad);
03119 
03120                   TClonesArray * clones = (TClonesArray*)leafinfo->GetValuePointer(leafcur,0);
03121 
03122                   delete leafinfo; clonesinfo = 0;
03123                   // If TClonesArray object does not exist we have no information, so let go
03124                   // on.  This is a weakish test since the TClonesArray object might exist in
03125                   // the next entry ... In other word, we ONLY rely on the information available
03126                   // in entry #0.
03127                   if (!clones) continue;
03128                   TClass *sub_cl = clones->GetClass();
03129 
03130                   // Now that we finally have the inside class, let's query it.
03131                   element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(nextchoice,offset);
03132                   if (element) break;
03133                } // if clones array
03134                else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {
03135 
03136                   TClass *sub_cl = curelem->GetClassPointer()->GetCollectionProxy()->GetValueClass();
03137 
03138                   while(sub_cl && sub_cl->GetCollectionProxy())
03139                      sub_cl = sub_cl->GetCollectionProxy()->GetValueClass();
03140 
03141                   // Now that we finally have the inside class, let's query it.
03142                   if (sub_cl) element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(nextchoice,offset);
03143                   if (element) break;
03144 
03145                }
03146             } // loop on elements
03147          }
03148          if (element) break;
03149          else cl = 0;
03150       }
03151    }
03152    delete clonesinfo;
03153    if (cl) {
03154       return leafcur;
03155    } else {
03156       return 0;
03157    }
03158 }
03159 
03160 //______________________________________________________________________________
03161 Bool_t TTreeFormula::BranchHasMethod(TLeaf* leafcur, TBranch* branch, const char* method, const char* params, Long64_t readentry) const
03162 {
03163    // Return the leaf (if any) of the tree with contains an object of a class
03164    // having a method which has the name provided in the argument.
03165 
03166    TClass *cl = 0;
03167    TLeafObject* lobj = 0;
03168 
03169    // Since the user does not want this branch to be loaded anyway, we just
03170    // skip it.  This prevents us from warning the user that the method might
03171    // be on a disabled branch.  However, and more usefully, this allows the
03172    // user to avoid error messages from branches that cannot be currently
03173    // read without warnings/errors.
03174 
03175    if (branch->TestBit(kDoNotProcess)) {
03176       return kFALSE;
03177    }
03178 
03179    // FIXME: The following code is used somewhere else, we need to factor it out.
03180    if (branch->InheritsFrom(TBranchObject::Class())) {
03181       lobj = (TLeafObject*) branch->GetListOfLeaves()->At(0);
03182       cl = lobj->GetClass();
03183    } else if (branch->InheritsFrom(TBranchElement::Class())) {
03184       TBranchElement* branchEl = (TBranchElement*) branch;
03185       Int_t type = branchEl->GetStreamerType();
03186       if (type == -1) {
03187          cl = branchEl->GetInfo()->GetClass();
03188       } else if (type > 60) {
03189          // Case of an object data member.  Here we allow for the
03190          // variable name to be ommitted.  Eg, for Event.root with split
03191          // level 1 or above  Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
03192          TStreamerElement* element = (TStreamerElement*) branchEl->GetInfo()->GetElems()[branchEl->GetID()];
03193          if (element) {
03194             cl = element->GetClassPointer();
03195          } else {
03196             cl = 0;
03197          }
03198          if ((cl == TClonesArray::Class()) && (branchEl->GetType() == 31)) {
03199             // we have a TClonesArray inside a split TClonesArray,
03200             // Let's not dig any further.  If the user really wants a data member
03201             // inside the nested TClonesArray, it has to specify it explicitly.
03202             cl = 0;
03203          }
03204          // NOTE do we need code for Collection here?
03205       }
03206    }
03207 
03208    if (cl == TClonesArray::Class()) {
03209       // We might be try to call a method of the top class inside a
03210       // TClonesArray.
03211       // Since the leaf was not terminal, we might have a split or
03212       // unsplit and/or top leaf/branch.
03213       TClonesArray* clones = 0;
03214       R__LoadBranch(branch, readentry, fQuickLoad);
03215       if (branch->InheritsFrom(TBranchObject::Class())) {
03216          clones = (TClonesArray*) lobj->GetObject();
03217       } else if (branch->InheritsFrom(TBranchElement::Class())) {
03218          // We do not know exactly where the leaf of the TClonesArray is
03219          // in the hierachy but we still need to get the correct class
03220          // holder.
03221          TBranchElement* bc = (TBranchElement*) branch;
03222          if (bc == bc->GetMother()) {
03223             // Top level branch
03224             //clones = *((TClonesArray**) bc->GetAddress());
03225             clones = (TClonesArray*) bc->GetObject();
03226          } else if (!leafcur || !leafcur->IsOnTerminalBranch()) {
03227             TStreamerElement* element = (TStreamerElement*) bc->GetInfo()->GetElems()[bc->GetID()];
03228             if (element->IsaPointer()) {
03229                clones = *((TClonesArray**) bc->GetAddress());
03230                //clones = *((TClonesArray**) bc->GetObject());
03231             } else {
03232                //clones = (TClonesArray*) bc->GetAddress();
03233                clones = (TClonesArray*) bc->GetObject();
03234             }
03235          }
03236          if (!clones) {
03237             R__LoadBranch(bc, readentry, fQuickLoad);
03238             TClass* mother_cl;
03239             mother_cl = bc->GetInfo()->GetClass();
03240             TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0);
03241             // if (!leafcur) { leafcur = (TLeaf*) branch->GetListOfLeaves()->At(0); }
03242             clones = (TClonesArray*) clonesinfo->GetLocalValuePointer(leafcur, 0);
03243             // cl = clones->GetClass();
03244             delete clonesinfo;
03245          }
03246       } else {
03247          Error("BranchHasMethod","A TClonesArray was stored in a branch type no yet support (i.e. neither TBranchObject nor TBranchElement): %s",branch->IsA()->GetName());
03248          return kFALSE;
03249       }
03250       cl = clones->GetClass();
03251    } else if (cl && cl->GetCollectionProxy()) {
03252       cl = cl->GetCollectionProxy()->GetValueClass();
03253    }
03254 
03255    if (cl) {
03256       if (cl->GetClassInfo()) {
03257          if (cl->GetMethodAllAny(method)) {
03258             // Let's try to see if the function we found belongs to the current
03259             // class.  Note that this implementation currently can not work if
03260             // one the argument is another leaf or data member of the object.
03261             // (Anyway we do NOT support this case).
03262             TMethodCall* methodcall = new TMethodCall(cl, method, params);
03263             if (methodcall->GetMethod()) {
03264                // We have a method that works.
03265                // We will use it.
03266                return kTRUE;
03267             }
03268             delete methodcall;
03269          }
03270       }
03271    }
03272 
03273    return kFALSE;
03274 }
03275 
03276 //______________________________________________________________________________
03277 Int_t TTreeFormula::GetRealInstance(Int_t instance, Int_t codeindex) {
03278       // Now let calculate what physical instance we really need.
03279       // Some redundant code is used to speed up the cases where
03280       // they are no dimensions.
03281       // We know that instance is less that fCumulUsedSize[0] so
03282       // we can skip the modulo when virt_dim is 0.
03283       Int_t real_instance = 0;
03284       Int_t virt_dim;
03285 
03286       Bool_t check = kFALSE;
03287       if (codeindex<0) {
03288          codeindex = 0;
03289          check = kTRUE;
03290       }
03291 
03292       TFormLeafInfo * info = 0;
03293       Int_t max_dim = fNdimensions[codeindex];
03294       if ( max_dim ) {
03295          virt_dim = 0;
03296          max_dim--;
03297 
03298          if (!fManager->fMultiVarDim) {
03299             if (fIndexes[codeindex][0]>=0) {
03300                real_instance = fIndexes[codeindex][0] * fCumulSizes[codeindex][1];
03301             } else {
03302                Int_t local_index;
03303                local_index = ( instance / fManager->fCumulUsedSizes[virt_dim+1]);
03304                if (fIndexes[codeindex][0]==-2) {
03305                   // NOTE: Should we check that this is a valid index?
03306                   if (check) {
03307                      Int_t index_real_instance = fVarIndexes[codeindex][0]->GetRealInstance(local_index,-1);
03308                      if (index_real_instance > fVarIndexes[codeindex][0]->fNdata[0]) {
03309                         // out of bounds
03310                         return fNdata[0]+1;
03311                      }
03312                   }
03313                   if (fDidBooleanOptimization && local_index!=0) {
03314                      // Force the loading of the index.
03315                      fVarIndexes[codeindex][0]->LoadBranches();
03316                   }
03317                   local_index = (Int_t)fVarIndexes[codeindex][0]->EvalInstance(local_index);
03318                   if (local_index<0) {
03319                      Error("EvalInstance","Index %s is out of bound (%d) in formula %s",
03320                            fVarIndexes[codeindex][0]->GetTitle(),
03321                            local_index,
03322                            GetTitle());
03323                      return fNdata[0]+1;
03324                   }
03325                }
03326                real_instance = local_index * fCumulSizes[codeindex][1];
03327                virt_dim ++;
03328             }
03329          } else {
03330             // NOTE: We assume that ONLY the first dimension of a leaf can have a variable
03331             // size AND contain the index for the size of yet another sub-dimension.
03332             // I.e. a variable size array inside a variable size array can only have its
03333             // size vary with the VERY FIRST physical dimension of the leaf.
03334             // Thus once the index of the first dimension is found, all other dimensions
03335             // are fixed!
03336 
03337             // NOTE: We could unroll some of this loops to avoid a few tests.
03338             if (fHasMultipleVarDim[codeindex]) {
03339                info = (TFormLeafInfo *)(fDataMembers.At(codeindex));
03340                // if (info && info->GetVarDim()==-1) info = 0;
03341             }
03342             Int_t local_index;
03343 
03344             switch (fIndexes[codeindex][0]) {
03345             case -2:
03346                if (fDidBooleanOptimization && instance!=0) {
03347                   // Force the loading of the index.
03348                   fVarIndexes[codeindex][0]->LoadBranches();
03349                }
03350                local_index = (Int_t)fVarIndexes[codeindex][0]->EvalInstance(instance);
03351                if (local_index<0) {
03352                   Error("EvalInstance","Index %s is out of bound (%d) in formula %s",
03353                         fVarIndexes[codeindex][0]->GetTitle(),
03354                         local_index,
03355                         GetTitle());
03356                   local_index = 0;
03357                }
03358                break;
03359             case -1: {
03360                   local_index = 0;
03361                   Int_t virt_accum = 0;
03362                   Int_t maxloop = fManager->fCumulUsedVarDims->GetSize();
03363                   if (maxloop == 0) {
03364                      local_index--;
03365                      instance = fNdata[0]+1; // out of bounds.
03366                      if (check) return fNdata[0]+1;
03367                   } else {
03368                      do {
03369                         virt_accum += fManager->fCumulUsedVarDims->GetArray()[local_index];
03370                         local_index++;
03371                      } while( instance >= virt_accum && local_index<maxloop);
03372                      if (local_index==maxloop && (instance >= virt_accum)) {
03373                         local_index--;
03374                         instance = fNdata[0]+1; // out of bounds.
03375                         if (check) return fNdata[0]+1;
03376                      } else {
03377                         local_index--;
03378                         if (fManager->fCumulUsedVarDims->At(local_index)) {
03379                            instance -= (virt_accum - fManager->fCumulUsedVarDims->At(local_index));
03380                         } else {
03381                            instance = fNdata[0]+1; // out of bounds.
03382                            if (check) return fNdata[0]+1;
03383                         }
03384                      }
03385                   }
03386                   virt_dim ++;
03387                }
03388                break;
03389             default:
03390                local_index = fIndexes[codeindex][0];
03391             }
03392 
03393             // Inform the (appropriate) MultiVarLeafInfo that the clones array index is
03394             // local_index.
03395 
03396             if (fManager->fVarDims[kMAXFORMDIM]) {
03397                fManager->fCumulUsedSizes[kMAXFORMDIM] = fManager->fVarDims[kMAXFORMDIM]->At(local_index);
03398             } else {
03399                fManager->fCumulUsedSizes[kMAXFORMDIM] = fManager->fUsedSizes[kMAXFORMDIM];
03400             }
03401             for(Int_t d = kMAXFORMDIM-1; d>0; d--) {
03402                if (fManager->fVarDims[d]) {
03403                   fManager->fCumulUsedSizes[d] = fManager->fCumulUsedSizes[d+1] * fManager->fVarDims[d]->At(local_index);
03404                } else {
03405                   fManager->fCumulUsedSizes[d] = fManager->fCumulUsedSizes[d+1] * fManager->fUsedSizes[d];
03406                }
03407             }
03408             if (info) {
03409                // When we have multiple variable dimensions, the LeafInfo only expect
03410                // the instance after the primary index has been set.
03411                info->SetPrimaryIndex(local_index);
03412                real_instance = 0;
03413 
03414                // Let's update fCumulSizes for the rest of the code.
03415                Int_t vdim = info->GetVarDim();
03416                Int_t isize = info->GetSize(local_index);
03417                if (fIndexes[codeindex][vdim]>=0) {
03418                   info->SetSecondaryIndex(fIndexes[codeindex][vdim]); 
03419                }
03420                if  (isize!=1 && fIndexes[codeindex][vdim]>isize) {
03421                   // We are out of bounds!
03422                   return fNdata[0]+1;
03423                }
03424                fCumulSizes[codeindex][vdim] =  isize*fCumulSizes[codeindex][vdim+1];
03425                for(Int_t k=vdim -1; k>0; --k) {
03426                   fCumulSizes[codeindex][k] = fCumulSizes[codeindex][k+1]*fFixedSizes[codeindex][k];
03427                }
03428             } else {
03429                real_instance = local_index * fCumulSizes[codeindex][1];
03430             }
03431          }
03432          if (max_dim>0) {
03433             for (Int_t dim = 1; dim < max_dim; dim++) {
03434                if (fIndexes[codeindex][dim]>=0) {
03435                   real_instance += fIndexes[codeindex][dim] * fCumulSizes[codeindex][dim+1];
03436                } else {
03437                   Int_t local_index;
03438                   if (virt_dim && fManager->fCumulUsedSizes[virt_dim]>1) {
03439                      local_index = ( ( instance % fManager->fCumulUsedSizes[virt_dim] )
03440                                      / fManager->fCumulUsedSizes[virt_dim+1]);
03441                   } else {
03442                      local_index = ( instance / fManager->fCumulUsedSizes[virt_dim+1]);
03443                   }
03444                   if (fIndexes[codeindex][dim]==-2) {
03445                      // NOTE: Should we check that this is a valid index?
03446                      if (fDidBooleanOptimization && local_index!=0) {
03447                         // Force the loading of the index.
03448                         fVarIndexes[codeindex][dim]->LoadBranches();
03449                      }
03450                      local_index = (Int_t)fVarIndexes[codeindex][dim]->EvalInstance(local_index);
03451                      if (local_index<0 ||
03452                          local_index>=(fCumulSizes[codeindex][dim]/fCumulSizes[codeindex][dim+1])) {
03453                         Error("EvalInstance","Index %s is out of bound (%d/%d) in formula %s",
03454                               fVarIndexes[codeindex][dim]->GetTitle(),
03455                               local_index,
03456                               (fCumulSizes[codeindex][dim]/fCumulSizes[codeindex][dim+1]),
03457                               GetTitle());
03458                         local_index = (fCumulSizes[codeindex][dim]/fCumulSizes[codeindex][dim+1])-1;
03459                      }
03460                   }
03461                   real_instance += local_index * fCumulSizes[codeindex][dim+1];
03462                   virt_dim ++;
03463                }
03464             }
03465             if (fIndexes[codeindex][max_dim]>=0) {
03466                if (!info) real_instance += fIndexes[codeindex][max_dim];
03467             } else {
03468                Int_t local_index;
03469                if (virt_dim && fManager->fCumulUsedSizes[virt_dim]>1) {
03470                   local_index = instance % fManager->fCumulUsedSizes[virt_dim];
03471                } else {
03472                   local_index = instance;
03473                }
03474                if (info && local_index>=fCumulSizes[codeindex][max_dim]) {
03475                   // We are out of bounds! [Multiple var dims, See same message a few line above]
03476                   return fNdata[0]+1;
03477                }
03478                if (fIndexes[codeindex][max_dim]==-2) {
03479                   if (fDidBooleanOptimization && local_index!=0) {
03480                      // Force the loading of the index.
03481                      fVarIndexes[codeindex][max_dim]->LoadBranches();
03482                   }
03483                   local_index = (Int_t)fVarIndexes[codeindex][max_dim]->EvalInstance(local_index);
03484                   if (local_index<0 ||
03485                          local_index>=fCumulSizes[codeindex][max_dim]) {
03486                      Error("EvalInstance","Index %s is of out bound (%d/%d) in formula %s",
03487                            fVarIndexes[codeindex][max_dim]->GetTitle(),
03488                            local_index,
03489                            fCumulSizes[codeindex][max_dim],
03490                            GetTitle());
03491                      local_index = fCumulSizes[codeindex][max_dim]-1;
03492                   }
03493                }
03494                real_instance += local_index;
03495             }
03496          } // if (max_dim-1>0)
03497       } // if (max_dim)
03498 
03499       return real_instance;
03500 }
03501 
03502 //______________________________________________________________________________
03503 TClass* TTreeFormula::EvalClass() const
03504 {
03505 //  Evaluate the class of this treeformula
03506 //
03507 //  If the 'value' of this formula is a simple pointer to an object,
03508 //  this function returns the TClass corresponding to its type.
03509 
03510    if (fNoper != 1 || fNcodes <=0 ) return 0;
03511 
03512    return EvalClass(0);
03513 }
03514 
03515 //______________________________________________________________________________
03516 TClass* TTreeFormula::EvalClass(Int_t oper) const
03517 {
03518 //  Evaluate the class of the operation oper
03519 //
03520 //  If the 'value' in the requested operation is a simple pointer to an object,
03521 //  this function returns the TClass corresponding to its type.
03522 
03523    TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(oper);
03524    switch(fLookupType[oper]) {
03525       case kDirect: {
03526          if (leaf->IsA()==TLeafObject::Class()) {
03527             return ((TLeafObject*)leaf)->GetClass();
03528          } else if ( leaf->IsA()==TLeafElement::Class()) {
03529             TBranchElement * branch = (TBranchElement*)((TLeafElement*)leaf)->GetBranch();
03530             TStreamerInfo * info = branch->GetInfo();
03531             Int_t id = branch->GetID();
03532             if (id>=0) {
03533                if (info==0 || info->GetElems()==0) {
03534                   // we probably do not have a way to know the class of the object.
03535                   return 0;
03536                }
03537                TStreamerElement* elem = (TStreamerElement*)info->GetElems()[id];
03538                if (elem==0) {
03539                   // we probably do not have a way to know the class of the object.
03540                   return 0;
03541                } else {
03542                   return TClass::GetClass( elem->GetTypeName() );
03543                }
03544             } else return TClass::GetClass( branch->GetClassName() );
03545          } else {
03546             return 0;
03547          }
03548       }
03549       case kMethod: return 0; // kMethod is deprecated so let's no waste time implementing this.
03550       case kTreeMember:
03551       case kDataMember: {
03552          TObject *obj = fDataMembers.UncheckedAt(oper);
03553          if (!obj) return 0;
03554          return ((TFormLeafInfo*)obj)->GetClass();
03555       }
03556 
03557       default: return 0;
03558    }
03559 
03560 
03561 }
03562 
03563 //______________________________________________________________________________
03564 void* TTreeFormula::EvalObject(int instance)
03565 {
03566 //*-*-*-*-*-*-*-*-*-*-*Evaluate this treeformula*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
03567 //*-*                  =========================
03568 //
03569 //  Return the address of the object pointed to by the formula.
03570 //  Return 0 if the formula is not a single object
03571 //  The object type can be retrieved using by call EvalClass();
03572 
03573    if (fNoper != 1 || fNcodes <=0 ) return 0;
03574 
03575 
03576    switch (fLookupType[0]) {
03577       case kIndexOfEntry:
03578       case kIndexOfLocalEntry:
03579       case kEntries:
03580       case kLength:
03581       case kLengthFunc:
03582       case kIteration:
03583       case kEntryList:
03584          return 0;
03585    }
03586 
03587    TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);
03588 
03589    Int_t real_instance = GetRealInstance(instance,0);
03590 
03591    if (instance==0 || fNeedLoading) {
03592       fNeedLoading = kFALSE;
03593       R__LoadBranch(leaf->GetBranch(),
03594                     leaf->GetBranch()->GetTree()->GetReadEntry(),
03595                     fQuickLoad);
03596    }
03597    else if (real_instance>fNdata[0]) return 0;
03598    if (fAxis) {
03599       return 0;
03600    }
03601    switch(fLookupType[0]) {
03602       case kDirect: {
03603          if (real_instance) {
03604             Warning("EvalObject","Not yet implement for kDirect and arrays (for %s).\nPlease contact the developers",GetName());
03605          }
03606          return leaf->GetValuePointer();
03607       }
03608       case kMethod: return GetValuePointerFromMethod(0,leaf);
03609       case kTreeMember:
03610       case kDataMember: return ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->GetValuePointer(leaf,real_instance);
03611       default: return 0;
03612    }
03613 
03614 
03615 }
03616 
03617 
03618 //______________________________________________________________________________
03619 const char* TTreeFormula::EvalStringInstance(Int_t instance)
03620 {
03621    // Eval the instance as a string.
03622 
03623    const Int_t kMAXSTRINGFOUND = 10;
03624    const char *stringStack[kMAXSTRINGFOUND];
03625 
03626    if (fNoper==1 && fNcodes>0 && IsString()) {
03627       TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);
03628 
03629       Int_t real_instance = GetRealInstance(instance,0);
03630 
03631       if (instance==0 || fNeedLoading) {
03632          fNeedLoading = kFALSE;
03633          TBranch *branch = leaf->GetBranch();
03634          R__LoadBranch(branch,branch->GetTree()->GetReadEntry(),fQuickLoad);
03635       } else if (real_instance>=fNdata[0]) {
03636          return 0;
03637       }
03638 
03639       if (fLookupType[0]==kDirect) {
03640          return (char*)leaf->GetValuePointer();
03641       } else {
03642          return  (char*)GetLeafInfo(0)->GetValuePointer(leaf,real_instance);
03643       }
03644    }
03645 
03646    EvalInstance(instance,stringStack);
03647 
03648    return stringStack[0];
03649 }
03650 
03651 #define TT_EVAL_INIT                                                                            \
03652    TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);                                                \
03653                                                                                                 \
03654    const Int_t real_instance = GetRealInstance(instance,0);                                     \
03655                                                                                                 \
03656    if (instance==0) fNeedLoading = kTRUE;                                                       \
03657    if (real_instance>fNdata[0]) return 0;                                                       \
03658                                                                                                 \
03659    /* Since the only operation in this formula is reading this branch,                          \
03660       we are guaranteed that this function is first called with instance==0 and                 \
03661       hence we are guaranteed that the branch is always properly read */                        \
03662                                                                                                 \
03663    if (fNeedLoading) {                                                                          \
03664       fNeedLoading = kFALSE;                                                                    \
03665       TBranch *br = leaf->GetBranch();                                                          \
03666       Long64_t tentry = br->GetTree()->GetReadEntry();                                          \
03667       R__LoadBranch(br,tentry,fQuickLoad);                                                      \
03668    }                                                                                            \
03669                                                                                                 \
03670    if (fAxis) {                                                                                 \
03671       char * label;                                                                             \
03672       /* This portion is a duplicate (for speed reason) of the code                             \
03673          located  in the main for loop at "a tree string" (and in EvalStringInstance) */        \
03674       if (fLookupType[0]==kDirect) {                                                            \
03675          label = (char*)leaf->GetValuePointer();                                                \
03676       } else {                                                                                  \
03677          label = (char*)GetLeafInfo(0)->GetValuePointer(leaf,instance);                         \
03678       }                                                                                         \
03679       Int_t bin = fAxis->FindBin(label);                                                        \
03680       return bin-0.5;                                                                           \
03681    }
03682 
03683 #define TREE_EVAL_INIT                                                                          \
03684    const Int_t real_instance = GetRealInstance(instance,0);                                     \
03685                                                                                                 \
03686    if (real_instance>fNdata[0]) return 0;                                                       \
03687                                                                                                 \
03688    if (fAxis) {                                                                                 \
03689       char * label;                                                                             \
03690       /* This portion is a duplicate (for speed reason) of the code                             \
03691          located  in the main for loop at "a tree string" (and in EvalStringInstance) */        \
03692       label = (char*)GetLeafInfo(0)->GetValuePointer((TLeaf*)0x0,instance);                     \
03693       Int_t bin = fAxis->FindBin(label);                                                        \
03694       return bin-0.5;                                                                           \
03695    }
03696 
03697 #define TT_EVAL_INIT_LOOP                                                                       \
03698    TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(code);                                             \
03699                                                                                                 \
03700    /* Now let calculate what physical instance we really need.  */                              \
03701    const Int_t real_instance = GetRealInstance(instance,code);                                  \
03702                                                                                                 \
03703    if (willLoad) {                                                                              \
03704       TBranch *branch = (TBranch*)fBranches.UncheckedAt(code);                                  \
03705       if (branch) {                                                                             \
03706          Long64_t treeEntry = branch->GetTree()->GetReadEntry();                                \
03707          R__LoadBranch(branch,treeEntry,fQuickLoad);                                            \
03708       } else if (fDidBooleanOptimization) {                                                     \
03709          branch = leaf->GetBranch();                                                            \
03710          Long64_t treeEntry = branch->GetTree()->GetReadEntry();                                \
03711          if (branch->GetReadEntry() != treeEntry) branch->GetEntry( treeEntry );                \
03712       }                                                                                         \
03713    } else {                                                                                     \
03714       /* In the cases where we are behind (i.e. right of) a potential boolean optimization      \
03715          this tree variable reading may have not been executed with instance==0 which would     \
03716          result in the branch being potentially not read in. */                                 \
03717       if (fDidBooleanOptimization) {                                                            \
03718          TBranch *br = leaf->GetBranch();                                                       \
03719          Long64_t treeEntry = br->GetTree()->GetReadEntry();                                    \
03720          if (br->GetReadEntry() != treeEntry) br->GetEntry( treeEntry );                        \
03721       }                                                                                         \
03722    }                                                                                            \
03723    if (real_instance>fNdata[code]) return 0;
03724 
03725 #define TREE_EVAL_INIT_LOOP                                                                     \
03726    /* Now let calculate what physical instance we really need.  */                              \
03727    const Int_t real_instance = GetRealInstance(instance,code);                                  \
03728                                                                                                 \
03729    if (real_instance>fNdata[code]) return 0;
03730 
03731 namespace {
03732    Double_t Summing(TTreeFormula *sum) {
03733       Int_t len = sum->GetNdata();
03734       Double_t res = 0;
03735       for (int i=0; i<len; ++i) res += sum->EvalInstance(i);
03736       return res;
03737    }
03738    Double_t FindMin(TTreeFormula *arr) {
03739       Int_t len = arr->GetNdata();
03740       Double_t res = 0;
03741       if (len) {
03742          res = arr->EvalInstance(0);
03743          for (int i=1; i<len; ++i) {
03744             Double_t val = arr->EvalInstance(i);
03745             if (val < res) {
03746                res = val;
03747             }
03748          }
03749       }
03750       return res;
03751    }
03752    Double_t FindMax(TTreeFormula *arr) {
03753       Int_t len = arr->GetNdata();
03754       Double_t res = 0;
03755       if (len) {
03756          res = arr->EvalInstance(0);
03757          for (int i=1; i<len; ++i) {
03758             Double_t val = arr->EvalInstance(i);
03759             if (val > res) {
03760                res = val;
03761             }
03762          }
03763       }
03764       return res;
03765    }
03766    Double_t FindMin(TTreeFormula *arr, TTreeFormula *condition) {
03767       Int_t len = arr->GetNdata();
03768       Double_t res = 0;
03769       if (len) {
03770          int i = 0;
03771          Double_t condval;
03772          do {
03773             condval = condition->EvalInstance(i);
03774             ++i;
03775          } while (!condval && i<len);
03776          if (i==len) {
03777             return 0;
03778          }
03779          if (i!=1) {
03780             // Insure the loading of the branch.
03781             arr->EvalInstance(0);
03782          }
03783          // Now we know that i>0 && i<len and cond==true
03784          res = arr->EvalInstance(i-1);
03785          for (; i<len; ++i) {
03786             condval = condition->EvalInstance(i);
03787             if (condval) {
03788                Double_t val = arr->EvalInstance(i);
03789                if (val < res) {
03790                   res = val;
03791                }
03792             }
03793          }
03794       }
03795       return res;
03796    }
03797    Double_t FindMax(TTreeFormula *arr, TTreeFormula *condition) {
03798       Int_t len = arr->GetNdata();
03799       Double_t res = 0;
03800       if (len) {
03801          int i = 0;
03802          Double_t condval;
03803          do {
03804             condval = condition->EvalInstance(i);
03805             ++i;
03806          } while (!condval && i<len);
03807          if (i==len) {
03808             return 0;
03809          }
03810          if (i!=1) {
03811             // Insure the loading of the branch.
03812             arr->EvalInstance(0);
03813          }
03814          // Now we know that i>0 && i<len and cond==true
03815          res = arr->EvalInstance(i-1);
03816          for (; i<len; ++i) {
03817             condval = condition->EvalInstance(i);
03818             if (condval) {
03819                Double_t val = arr->EvalInstance(i);
03820                if (val > res) {
03821                   res = val;
03822                }
03823             }
03824          }
03825       }
03826       return res;
03827    }
03828 }
03829 
03830 //______________________________________________________________________________
03831 Double_t TTreeFormula::EvalInstance(Int_t instance, const char *stringStackArg[])
03832 {
03833 //*-*-*-*-*-*-*-*-*-*-*Evaluate this treeformula*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
03834 //*-*                  =========================
03835 //
03836 
03837 // Note that the redundance and structure in this code is tailored to improve
03838 // efficiencies.
03839 
03840    if (TestBit(kMissingLeaf)) return 0;
03841    if (fNoper == 1 && fNcodes > 0) {
03842 
03843       switch (fLookupType[0]) {
03844          case kDirect:     {
03845             TT_EVAL_INIT;
03846             Double_t result = leaf->GetValue(real_instance);
03847             return result;
03848          }
03849          case kMethod:     {
03850             TT_EVAL_INIT;
03851             ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->SetBranch(leaf->GetBranch());
03852             return GetValueFromMethod(0,leaf);
03853          }
03854          case kDataMember: {
03855             TT_EVAL_INIT;
03856             ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->SetBranch(leaf->GetBranch());
03857             return ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->GetValue(leaf,real_instance);
03858          }
03859          case kTreeMember: {
03860             TREE_EVAL_INIT;
03861             return ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->GetValue((TLeaf*)0x0,real_instance);
03862          }
03863          case kIndexOfEntry: return (Double_t)fTree->GetReadEntry();
03864          case kIndexOfLocalEntry: return (Double_t)fTree->GetTree()->GetReadEntry();
03865          case kEntries:      return (Double_t)fTree->GetEntries();
03866          case kLength:       return fManager->fNdata;
03867          case kLengthFunc:   return ((TTreeFormula*)fAliases.UncheckedAt(0))->GetNdata();
03868          case kIteration:    return instance;
03869          case kSum:          return Summing((TTreeFormula*)fAliases.UncheckedAt(0));
03870          case kMin:          return FindMin((TTreeFormula*)fAliases.UncheckedAt(0));
03871          case kMax:          return FindMax((TTreeFormula*)fAliases.UncheckedAt(0));
03872          case kEntryList: {
03873             TEntryList *elist = (TEntryList*)fExternalCuts.At(0);
03874             return elist->Contains(fTree->GetTree()->GetReadEntry());
03875          }
03876          case -1: break;
03877       }
03878       switch (fCodes[0]) {
03879          case -2: {
03880             TCutG *gcut = (TCutG*)fExternalCuts.At(0);
03881             TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
03882             TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
03883             Double_t xcut = fx->EvalInstance(instance);
03884             Double_t ycut = fy->EvalInstance(instance);
03885             return gcut->IsInside(xcut,ycut);
03886          }
03887          case -1: {
03888             TCutG *gcut = (TCutG*)fExternalCuts.At(0);
03889             TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
03890             return fx->EvalInstance(instance);
03891          }
03892          default: return 0;
03893       }
03894    }
03895 
03896    Double_t tab[kMAXFOUND];
03897    const Int_t kMAXSTRINGFOUND = 10;
03898    const char *stringStackLocal[kMAXSTRINGFOUND];
03899    const char **stringStack = stringStackArg?stringStackArg:stringStackLocal;
03900 
03901    const bool willLoad = (instance==0 || fNeedLoading); fNeedLoading = kFALSE;
03902    if (willLoad) fDidBooleanOptimization = kFALSE;
03903 
03904    Int_t pos  = 0;
03905    Int_t pos2 = 0;
03906    for (Int_t i=0; i<fNoper ; ++i) {
03907 
03908       const Int_t oper = GetOper()[i];
03909       const Int_t newaction = oper >> kTFOperShift;
03910 
03911       if (newaction<kDefinedVariable) {
03912          // TFormula operands.
03913 
03914          // one of the most used cases
03915          if (newaction==kConstant) { pos++; tab[pos-1] = fConst[(oper & kTFOperMask)]; continue; }
03916 
03917          switch(newaction) {
03918 
03919             case kEnd        : return tab[0];
03920             case kAdd        : pos--; tab[pos-1] += tab[pos]; continue;
03921             case kSubstract  : pos--; tab[pos-1] -= tab[pos]; continue;
03922             case kMultiply   : pos--; tab[pos-1] *= tab[pos]; continue;
03923             case kDivide     : pos--; if (tab[pos] == 0) tab[pos-1] = 0; //  division by 0
03924                                       else               tab[pos-1] /= tab[pos];
03925                                       continue;
03926             case kModulo     : {pos--;
03927                                 Long64_t int1((Long64_t)tab[pos-1]);
03928                                 Long64_t int2((Long64_t)tab[pos]);
03929                                 tab[pos-1] = Double_t(int1%int2);
03930                                 continue;}
03931 
03932             case kcos  : tab[pos-1] = TMath::Cos(tab[pos-1]); continue;
03933             case ksin  : tab[pos-1] = TMath::Sin(tab[pos-1]); continue;
03934             case ktan  : if (TMath::Cos(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
03935                          else tab[pos-1] = TMath::Tan(tab[pos-1]);
03936                          continue;
03937             case kacos : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} //  indetermination
03938                          else tab[pos-1] = TMath::ACos(tab[pos-1]);
03939                          continue;
03940             case kasin : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} //  indetermination
03941                          else tab[pos-1] = TMath::ASin(tab[pos-1]);
03942                          continue;
03943             case katan : tab[pos-1] = TMath::ATan(tab[pos-1]); continue;
03944             case kcosh : tab[pos-1] = TMath::CosH(tab[pos-1]); continue;
03945             case ksinh : tab[pos-1] = TMath::SinH(tab[pos-1]); continue;
03946             case ktanh : if (TMath::CosH(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
03947                          else tab[pos-1] = TMath::TanH(tab[pos-1]);
03948                          continue;
03949             case kacosh: if (tab[pos-1] < 1) {tab[pos-1] = 0;} //  indetermination
03950                          else tab[pos-1] = TMath::ACosH(tab[pos-1]);
03951                          continue;
03952             case kasinh: tab[pos-1] = TMath::ASinH(tab[pos-1]); continue;
03953             case katanh: if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
03954                      else tab[pos-1] = TMath::ATanH(tab[pos-1]); continue;
03955             case katan2: pos--; tab[pos-1] = TMath::ATan2(tab[pos-1],tab[pos]); continue;
03956 
03957             case kfmod : pos--; tab[pos-1] = fmod(tab[pos-1],tab[pos]); continue;
03958             case kpow  : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
03959             case ksq   : tab[pos-1] = tab[pos-1]*tab[pos-1]; continue;
03960             case ksqrt : tab[pos-1] = TMath::Sqrt(TMath::Abs(tab[pos-1])); continue;
03961 
03962             case kstrstr : pos2 -= 2; pos++;if (strstr(stringStack[pos2],stringStack[pos2+1])) tab[pos-1]=1;
03963                                         else tab[pos-1]=0; continue;
03964 
03965             case kmin : pos--; tab[pos-1] = TMath::Min(tab[pos-1],tab[pos]); continue;
03966             case kmax : pos--; tab[pos-1] = TMath::Max(tab[pos-1],tab[pos]); continue;
03967 
03968             case klog  : if (tab[pos-1] > 0) tab[pos-1] = TMath::Log(tab[pos-1]);
03969                          else {tab[pos-1] = 0;} //{indetermination }
03970                           continue;
03971             case kexp  : { Double_t dexp = tab[pos-1];
03972                            if (dexp < -700) {tab[pos-1] = 0; continue;}
03973                            if (dexp >  700) {tab[pos-1] = TMath::Exp(700); continue;}
03974                            tab[pos-1] = TMath::Exp(dexp); continue;
03975                          }
03976             case klog10: if (tab[pos-1] > 0) tab[pos-1] = TMath::Log10(tab[pos-1]);
03977                          else {tab[pos-1] = 0;} //{indetermination }
03978                          continue;
03979 
03980             case kpi   : pos++; tab[pos-1] = TMath::ACos(-1); continue;
03981 
03982             case kabs  : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
03983             case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1; continue;
03984             case kint  : tab[pos-1] = Double_t(Int_t(tab[pos-1])); continue;
03985             case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
03986             case krndm : pos++; tab[pos-1] = gRandom->Rndm(1); continue;
03987 
03988             case kAnd  : pos--; if (tab[pos-1]!=0 && tab[pos]!=0) tab[pos-1]=1;
03989                                 else tab[pos-1]=0; continue;
03990             case kOr   : pos--; if (tab[pos-1]!=0 || tab[pos]!=0) tab[pos-1]=1;
03991                                 else tab[pos-1]=0; continue;
03992 
03993             case kEqual      : pos--; tab[pos-1] = (tab[pos-1] == tab[pos]) ? 1 : 0; continue;
03994             case kNotEqual   : pos--; tab[pos-1] = (tab[pos-1] != tab[pos]) ? 1 : 0; continue;
03995             case kLess       : pos--; tab[pos-1] = (tab[pos-1] <  tab[pos]) ? 1 : 0; continue;
03996             case kGreater    : pos--; tab[pos-1] = (tab[pos-1] >  tab[pos]) ? 1 : 0; continue;
03997             case kLessThan   : pos--; tab[pos-1] = (tab[pos-1] <= tab[pos]) ? 1 : 0; continue;
03998             case kGreaterThan: pos--; tab[pos-1] = (tab[pos-1] >= tab[pos]) ? 1 : 0; continue;
03999             case kNot        :        tab[pos-1] = (tab[pos-1] !=        0) ? 0 : 1; continue;
04000 
04001             case kStringEqual : pos2 -= 2; pos++; if (!strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
04002                                                   else tab[pos-1]=0; continue;
04003             case kStringNotEqual: pos2 -= 2; pos++;if (strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
04004                                                    else tab[pos-1]=0; continue;
04005 
04006             case kBitAnd    : pos--; tab[pos-1]= ((Long64_t) tab[pos-1]) & ((Long64_t) tab[pos]); continue;
04007             case kBitOr     : pos--; tab[pos-1]= ((Long64_t) tab[pos-1]) | ((Long64_t) tab[pos]); continue;
04008             case kLeftShift : pos--; tab[pos-1]= ((Long64_t) tab[pos-1]) <<((Long64_t) tab[pos]); continue;
04009             case kRightShift: pos--; tab[pos-1]= ((Long64_t) tab[pos-1]) >>((Long64_t) tab[pos]); continue;
04010 
04011             case kJump   : i = (oper & kTFOperMask); continue;
04012             case kJumpIf : pos--; if (!tab[pos]) i = (oper & kTFOperMask); continue;
04013 
04014             case kStringConst: {
04015                // String
04016                pos2++; stringStack[pos2-1] = (char*)fExpr[i].Data();
04017                continue;
04018             }
04019 
04020             case kBoolOptimize: {
04021                // boolean operation optimizer
04022 
04023                int param = (oper & kTFOperMask);
04024                Bool_t skip = kFALSE;
04025                int op = param % 10; // 1 is && , 2 is ||
04026 
04027                if (op == 1 && (!tab[pos-1]) ) {
04028                   // &&: skip the right part if the left part is already false
04029 
04030                   skip = kTRUE;
04031 
04032                   // Preserve the existing behavior (i.e. the result of a&&b is
04033                   // either 0 or 1)
04034                   tab[pos-1] = 0;
04035 
04036                } else if (op == 2 && tab[pos-1] ) {
04037                   // ||: skip the right part if the left part is already true
04038 
04039                   skip = kTRUE;
04040 
04041                   // Preserve the existing behavior (i.e. the result of a||b is
04042                   // either 0 or 1)
04043                   tab[pos-1] = 1;
04044                }
04045 
04046                if (skip) {
04047                   int toskip = param / 10;
04048                   i += toskip;
04049                   if (willLoad) fDidBooleanOptimization = kTRUE;
04050               }
04051                continue;
04052             }
04053 
04054             case kFunctionCall: {
04055                // an external function call
04056 
04057                int param = (oper & kTFOperMask);
04058                int fno   = param / 1000;
04059                int nargs = param % 1000;
04060 
04061                // Retrieve the function
04062                TMethodCall *method = (TMethodCall*)fFunctions.At(fno);
04063 
04064                // Set the arguments
04065                method->ResetParam();
04066                if (nargs) {
04067                   UInt_t argloc = pos-nargs;
04068                   for(Int_t j=0;j<nargs;j++,argloc++,pos--) {
04069                      method->SetParam( tab[argloc] );
04070                   }
04071                }
04072                pos++;
04073                Double_t ret;
04074                method->Execute(ret);
04075                tab[pos-1] = ret; // check for the correct conversion!
04076 
04077                continue;
04078             }
04079 
04080 //         case kParameter:    { pos++; tab[pos-1] = fParams[(oper & kTFOperMask)]; continue; }
04081          }
04082 
04083       } else {
04084          // TTreeFormula operands.
04085 
04086          // a tree variable (the most used case).
04087 
04088          if (newaction == kDefinedVariable) {
04089 
04090             const Int_t code = (oper & kTFOperMask);
04091             const Int_t lookupType = fLookupType[code];
04092             switch (lookupType) {
04093                case kIndexOfEntry: tab[pos++] = (Double_t)fTree->GetReadEntry(); continue;
04094                case kIndexOfLocalEntry: tab[pos++] = (Double_t)fTree->GetTree()->GetReadEntry(); continue;
04095                case kEntries:      tab[pos++] = (Double_t)fTree->GetEntries(); continue;
04096                case kLength:       tab[pos++] = fManager->fNdata; continue;
04097                case kLengthFunc:   tab[pos++] = ((TTreeFormula*)fAliases.UncheckedAt(i))->GetNdata(); continue;
04098                case kIteration:    tab[pos++] = instance; continue;
04099                case kSum:          tab[pos++] = Summing((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
04100                case kMin:          tab[pos++] = FindMin((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
04101                case kMax:          tab[pos++] = FindMax((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
04102 
04103                case kDirect:     { TT_EVAL_INIT_LOOP; tab[pos++] = leaf->GetValue(real_instance); continue; }
04104                case kMethod:     { TT_EVAL_INIT_LOOP; tab[pos++] = GetValueFromMethod(code,leaf); continue; }
04105                case kDataMember: { TT_EVAL_INIT_LOOP; tab[pos++] = ((TFormLeafInfo*)fDataMembers.UncheckedAt(code))->
04106                                           GetValue(leaf,real_instance); continue; }
04107                case kTreeMember: { TREE_EVAL_INIT_LOOP; tab[pos++] = ((TFormLeafInfo*)fDataMembers.UncheckedAt(code))->
04108                                           GetValue((TLeaf*)0x0,real_instance); continue; }
04109                case kEntryList: { TEntryList *elist = (TEntryList*)fExternalCuts.At(code);
04110                   tab[pos++] = elist->Contains(fTree->GetReadEntry());
04111                   continue;}
04112                case -1: break;
04113                default: tab[pos++] = 0; continue;
04114             }
04115             switch (fCodes[code]) {
04116                case -2: {
04117                   TCutG *gcut = (TCutG*)fExternalCuts.At(code);
04118                   TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
04119                   TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
04120                   Double_t xcut = fx->EvalInstance(instance);
04121                   Double_t ycut = fy->EvalInstance(instance);
04122                   tab[pos++] = gcut->IsInside(xcut,ycut);
04123                   continue;
04124                }
04125                case -1: {
04126                   TCutG *gcut = (TCutG*)fExternalCuts.At(code);
04127                   TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
04128                   tab[pos++] = fx->EvalInstance(instance);
04129                   continue;
04130                }
04131                default: {
04132                   tab[pos++] = 0;
04133                   continue;
04134                }
04135             }
04136          }
04137          switch(newaction) {
04138 
04139             // a TTree Variable Alias (i.e. a sub-TTreeFormula)
04140             case kAlias: {
04141                int aliasN = i;
04142                TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(aliasN));
04143                R__ASSERT(subform);
04144 
04145                Double_t param = subform->EvalInstance(instance);
04146 
04147                tab[pos] = param; pos++;
04148                continue;
04149             }
04150             // a TTree Variable Alias String (i.e. a sub-TTreeFormula)
04151             case kAliasString: {
04152                int aliasN = i;
04153                TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(aliasN));
04154                R__ASSERT(subform);
04155 
04156                pos2++;
04157                stringStack[pos2-1] = subform->EvalStringInstance(instance);
04158                continue;
04159             }
04160             case kMinIf: {
04161                int alternateN = i;
04162                TTreeFormula *primary = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN));
04163                TTreeFormula *condition = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN+1));
04164                Double_t param = FindMin(primary,condition);
04165                ++i; // skip the place holder for the condition
04166                tab[pos] = param; pos++;
04167                continue;
04168             }
04169             case kMaxIf: {
04170                int alternateN = i;
04171                TTreeFormula *primary = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN));
04172                TTreeFormula *condition = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN+1));
04173                Double_t param = FindMax(primary,condition);
04174                ++i; // skip the place holder for the condition
04175                tab[pos] = param; pos++;
04176                continue;
04177             }
04178                
04179             // a TTree Variable Alternate (i.e. a sub-TTreeFormula)
04180             case kAlternate: {
04181                int alternateN = i;
04182                TTreeFormula *primary = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN));
04183 
04184                // First check whether we are in range for the primary formula
04185                if (instance < primary->GetNdata()) {
04186 
04187                   Double_t param = primary->EvalInstance(instance);
04188 
04189                   ++i; // skip the alternate value.
04190 
04191                   tab[pos] = param; pos++;
04192                } else {
04193                   // The primary is not in rancge, we will calculate the alternate value
04194                   // via the next operation (which will be a intentional).
04195 
04196                   // kAlias no operations
04197                }
04198                continue;
04199             }
04200             case kAlternateString: {
04201                int alternateN = i;
04202                TTreeFormula *primary = static_cast<TTreeFormula*>(fAliases.UncheckedAt(alternateN));
04203 
04204                // First check whether we are in range for the primary formula
04205                if (instance < primary->GetNdata()) {
04206 
04207                   pos2++;
04208                   stringStack[pos2-1] = primary->EvalStringInstance(instance);
04209 
04210                   ++i; // skip the alternate value.
04211 
04212                } else {
04213                   // The primary is not in rancge, we will calculate the alternate value
04214                   // via the next operation (which will be a kAlias).
04215 
04216                   // intentional no operations
04217                }
04218                continue;
04219             }
04220 
04221             // a tree string
04222             case kDefinedString: {
04223                Int_t string_code = (oper & kTFOperMask);
04224                TLeaf *leafc = (TLeaf*)fLeaves.UncheckedAt(string_code);
04225 
04226                // Now let calculate what physical instance we really need.
04227                const Int_t real_instance = GetRealInstance(instance,string_code);
04228 
04229                if (instance==0 || fNeedLoading) {
04230                   fNeedLoading = kFALSE;
04231                   TBranch *branch = leafc->GetBranch();
04232                   Long64_t readentry = branch->GetTree()->GetReadEntry();
04233                   R__LoadBranch(branch,readentry,fQuickLoad);
04234                } else {
04235                   // In the cases where we are behind (i.e. right of) a potential boolean optimization
04236                   // this tree variable reading may have not been executed with instance==0 which would
04237                   // result in the branch being potentially not read in.
04238                   if (fDidBooleanOptimization) {
04239                      TBranch *br = leafc->GetBranch();
04240                      Long64_t treeEntry = br->GetTree()->GetReadEntry();
04241                      R__LoadBranch(br,treeEntry,kTRUE);
04242                   }
04243                   if (real_instance>fNdata[string_code]) return 0;
04244                }
04245                pos2++;
04246                if (fLookupType[string_code]==kDirect) {
04247                   stringStack[pos2-1] = (char*)leafc->GetValuePointer();
04248                } else {
04249                   stringStack[pos2-1] = (char*)GetLeafInfo(string_code)->GetValuePointer(leafc,real_instance);
04250                }
04251                continue;
04252             }
04253 
04254          }
04255       }
04256 
04257       R__ASSERT(i<fNoper);
04258    }
04259 
04260    Double_t result = tab[0];
04261    return result;
04262 }
04263 
04264 //______________________________________________________________________________
04265 TFormLeafInfo *TTreeFormula::GetLeafInfo(Int_t code) const
04266 {
04267 //*-*-*-*-*-*-*-*Return DataMember corresponding to code*-*-*-*-*-*
04268 //*-*            =======================================
04269 //
04270 //  function called by TLeafObject::GetValue
04271 //  with the value of fLookupType computed in TTreeFormula::DefinedVariable
04272 
04273    return (TFormLeafInfo *)fDataMembers.UncheckedAt(code);
04274 
04275 }
04276 
04277 //______________________________________________________________________________
04278 TLeaf *TTreeFormula::GetLeaf(Int_t n) const
04279 {
04280 //*-*-*-*-*-*-*-*Return leaf corresponding to serial number n*-*-*-*-*-*
04281 //*-*            ============================================
04282 //
04283 
04284    return (TLeaf*)fLeaves.UncheckedAt(n);
04285 }
04286 
04287 //______________________________________________________________________________
04288 TMethodCall *TTreeFormula::GetMethodCall(Int_t code) const
04289 {
04290 //*-*-*-*-*-*-*-*Return methodcall corresponding to code*-*-*-*-*-*
04291 //*-*            =======================================
04292 //
04293 //  function called by TLeafObject::GetValue
04294 //  with the value of fLookupType computed in TTreeFormula::DefinedVariable
04295 
04296    return (TMethodCall *)fMethods.UncheckedAt(code);
04297 
04298 }
04299 
04300 //______________________________________________________________________________
04301 Int_t TTreeFormula::GetNdata()
04302 {
04303 //*-*-*-*-*-*-*-*Return number of available instances in the formula-*-*-*-*-*-*
04304 //*-*            ===================================================
04305 //
04306 
04307   return fManager->GetNdata();
04308 }
04309 
04310 //______________________________________________________________________________
04311 Double_t TTreeFormula::GetValueFromMethod(Int_t i, TLeaf* leaf) const
04312 {
04313    // Return result of a leafobject method.
04314 
04315    TMethodCall* m = GetMethodCall(i);
04316 
04317    if (!m) {
04318       return 0.0;
04319    }
04320 
04321    void* thisobj = 0;
04322    if (leaf->InheritsFrom(TLeafObject::Class())) {
04323       thisobj = ((TLeafObject*) leaf)->GetObject();
04324    } else {
04325       TBranchElement* branch = (TBranchElement*) ((TLeafElement*) leaf)->GetBranch();
04326       Int_t id = branch->GetID();
04327       // FIXME: This is wrong for a top-level branch.
04328       Int_t offset = 0;
04329       if (id > -1) {
04330          TStreamerInfo* info = branch->GetInfo();
04331          if (info) {
04332             offset = info->GetOffsets()[id];
04333          } else {
04334             Warning("GetValueFromMethod", "No streamer info for branch %s.", branch->GetName());
04335          }
04336       }
04337       if (id < 0) {
04338          char* address = branch->GetObject();
04339          thisobj = address;
04340       } else {
04341          //char* address = branch->GetAddress();
04342          char* address = branch->GetObject();
04343          if (address) {
04344             thisobj = *((char**) (address + offset));
04345          } else {
04346             // FIXME: If the address is not set, the object won't be either!
04347             thisobj = branch->GetObject();
04348          }
04349       }
04350    }
04351 
04352    TMethodCall::EReturnType r = m->ReturnType();
04353 
04354    if (r == TMethodCall::kLong) {
04355       Long_t l;
04356       m->Execute(thisobj, l);
04357       return (Double_t) l;
04358    }
04359 
04360    if (r == TMethodCall::kDouble) {
04361       Double_t d;
04362       m->Execute(thisobj, d);
04363       return d;
04364    }
04365 
04366    m->Execute(thisobj);
04367 
04368    return 0;
04369 }
04370 
04371 //______________________________________________________________________________
04372 void* TTreeFormula::GetValuePointerFromMethod(Int_t i, TLeaf* leaf) const
04373 {
04374    // Return result of a leafobject method.
04375 
04376    TMethodCall* m = GetMethodCall(i);
04377 
04378    if (!m) {
04379       return 0;
04380    }
04381 
04382    void* thisobj;
04383    if (leaf->InheritsFrom(TLeafObject::Class())) {
04384       thisobj = ((TLeafObject*) leaf)->GetObject();
04385    } else {
04386       TBranchElement* branch = (TBranchElement*) ((TLeafElement*) leaf)->GetBranch();
04387       Int_t id = branch->GetID();
04388       Int_t offset = 0;
04389       if (id > -1) {
04390          TStreamerInfo* info = branch->GetInfo();
04391          if (info) {
04392             offset = info->GetOffsets()[id];
04393          } else {
04394             Warning("GetValuePointerFromMethod", "No streamer info for branch %s.", branch->GetName());
04395          }
04396       }
04397       if (id < 0) {
04398          char* address = branch->GetObject();
04399          thisobj = address;
04400       } else {
04401          //char* address = branch->GetAddress();
04402          char* address = branch->GetObject();
04403          if (address) {
04404             thisobj = *((char**) (address + offset));
04405          } else {
04406             // FIXME: If the address is not set, the object won't be either!
04407             thisobj = branch->GetObject();
04408          }
04409       }
04410    }
04411 
04412    TMethodCall::EReturnType r = m->ReturnType();
04413 
04414    if (r == TMethodCall::kLong) {
04415       Long_t l;
04416       m->Execute(thisobj, l);
04417       return 0;
04418    }
04419 
04420    if (r == TMethodCall::kDouble) {
04421       Double_t d;
04422       m->Execute(thisobj, d);
04423       return 0;
04424    }
04425 
04426    if (r == TMethodCall::kOther) {
04427       char* c;
04428       m->Execute(thisobj, &c);
04429       return c;
04430    }
04431 
04432    m->Execute(thisobj);
04433 
04434    return 0;
04435 }
04436 
04437 //______________________________________________________________________________
04438 Bool_t TTreeFormula::IsInteger(Bool_t fast) const
04439 {
04440    // return TRUE if the formula corresponds to one single Tree leaf
04441    // and this leaf is short, int or unsigned short, int
04442    // When a leaf is of type integer or string, the generated histogram is forced
04443    // to have an integer bin width
04444 
04445    if (fast) {
04446       if (TestBit(kIsInteger)) return kTRUE;
04447       else                     return kFALSE;
04448    }
04449    
04450    if (fNoper==2 && GetAction(0)==kAlternate) {
04451       TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
04452       R__ASSERT(subform);
04453       return subform->IsInteger(kFALSE);
04454    }
04455    
04456    if (GetAction(0)==kMinIf || GetAction(0)==kMaxIf) {
04457       return kFALSE;
04458    }
04459 
04460    if (fNoper > 1) return kFALSE;
04461 
04462    if (GetAction(0)==kAlias) {
04463       TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
04464       R__ASSERT(subform);
04465       return subform->IsInteger(kFALSE);
04466    }
04467 
04468    if (fLeaves.GetEntries() != 1) {
04469       switch (fLookupType[0]) {
04470          case kIndexOfEntry:
04471          case kIndexOfLocalEntry:
04472          case kEntries:
04473          case kLength:
04474          case kLengthFunc:
04475          case kIteration:
04476            return kTRUE;
04477          case kSum:
04478          case kMin:
04479          case kMax:
04480          case kEntryList:
04481          default:
04482            return kFALSE;
04483       }
04484    }
04485 
04486    if (EvalClass()==TBits::Class()) return kTRUE;
04487 
04488    if (IsLeafInteger(0) || IsLeafString(0)) return kTRUE;
04489    return kFALSE;
04490 }
04491 
04492 //______________________________________________________________________________
04493 Bool_t TTreeFormula::IsLeafInteger(Int_t code) const
04494 {
04495    // return TRUE if the leaf corresponding to code is short, int or unsigned
04496    // short, int When a leaf is of type integer, the generated histogram is
04497    // forced to have an integer bin width
04498 
04499    TLeaf *leaf = (TLeaf*)fLeaves.At(code);
04500    if (!leaf) {
04501       switch (fLookupType[code]) {
04502          case kIndexOfEntry:
04503          case kIndexOfLocalEntry:
04504          case kEntries:
04505          case kLength:
04506          case kLengthFunc:
04507          case kIteration:
04508            return kTRUE;
04509          case kSum:
04510          case kMin:
04511          case kMax:
04512          case kEntryList:
04513          default:
04514            return kFALSE;
04515       }
04516    }
04517    if (fAxis) return kTRUE;
04518    TFormLeafInfo * info;
04519    switch (fLookupType[code]) {
04520       case kMethod:
04521       case kTreeMember:
04522       case kDataMember:
04523          info = GetLeafInfo(code);
04524          return info->IsInteger();
04525       case kDirect:
04526          break;
04527    }
04528    if (!strcmp(leaf->GetTypeName(),"Int_t"))    return kTRUE;
04529    if (!strcmp(leaf->GetTypeName(),"Short_t"))  return kTRUE;
04530    if (!strcmp(leaf->GetTypeName(),"UInt_t"))   return kTRUE;
04531    if (!strcmp(leaf->GetTypeName(),"UShort_t")) return kTRUE;
04532    if (!strcmp(leaf->GetTypeName(),"Bool_t"))   return kTRUE;
04533    if (!strcmp(leaf->GetTypeName(),"Char_t"))   return kTRUE;
04534    if (!strcmp(leaf->GetTypeName(),"UChar_t"))  return kTRUE;
04535    if (!strcmp(leaf->GetTypeName(),"string"))   return kTRUE;
04536    return kFALSE;
04537 }
04538 
04539 //______________________________________________________________________________
04540 Bool_t TTreeFormula::IsString() const
04541 {
04542    // return TRUE if the formula is a string
04543 
04544    return TestBit(kIsCharacter) || (fNoper==1 && IsString(0));
04545 }
04546 
04547 //______________________________________________________________________________
04548 Bool_t TTreeFormula::IsString(Int_t oper) const
04549 {
04550    // (fOper[i]>=105000 && fOper[i]<110000) || fOper[i] == kStrings)
04551 
04552    // return true if the expression at the index 'oper' is to be treated as
04553    // as string
04554 
04555    if (TFormula::IsString(oper)) return kTRUE;
04556    if (GetAction(oper)==kDefinedString) return kTRUE;
04557    if (GetAction(oper)==kAliasString) return kTRUE;
04558    if (GetAction(oper)==kAlternateString) return kTRUE;
04559    return kFALSE;
04560 }
04561 
04562 //______________________________________________________________________________
04563 Bool_t  TTreeFormula::IsLeafString(Int_t code) const
04564 {
04565    // return TRUE if the leaf or data member corresponding to code is a string
04566    TLeaf *leaf = (TLeaf*)fLeaves.At(code);
04567    TFormLeafInfo * info;
04568    if (fLookupType[code]==kTreeMember) {
04569       info = GetLeafInfo(code);
04570       return info->IsString();
04571    }
04572 
04573    switch(fLookupType[code]) {
04574       case kDirect:
04575          if ( !leaf->IsUnsigned() && (leaf->InheritsFrom(TLeafC::Class()) || leaf->InheritsFrom(TLeafB::Class()) ) ) {
04576             // Need to find out if it is an 'array' or a pointer.
04577             if (leaf->GetLenStatic() > 1) return kTRUE;
04578 
04579             // Now we need to differantiate between a variable length array and
04580             // a TClonesArray.
04581             if (leaf->GetLeafCount()) {
04582                const char* indexname = leaf->GetLeafCount()->GetName();
04583                if (indexname[strlen(indexname)-1] == '_' ) {
04584                   // This in a clones array
04585                   return kFALSE;
04586                } else {
04587                   // this is a variable length char array
04588                   return kTRUE;
04589                }
04590             }
04591             return kFALSE;
04592          } else if (leaf->InheritsFrom(TLeafElement::Class())) {
04593             TBranchElement * br = (TBranchElement*)leaf->GetBranch();
04594             Int_t bid = br->GetID();
04595             if (bid < 0) return kFALSE;
04596             if (br->GetInfo()==0 || br->GetInfo()->GetElems()==0) {
04597                // Case where the file is corrupted is some ways.
04598                // We can not get to the actual type of the data
04599                // let's assume it is NOT a string.
04600                return kFALSE;
04601             }
04602             TStreamerElement * elem = (TStreamerElement*) br->GetInfo()->GetElems()[bid];
04603             if (!elem) {
04604                // Case where the file is corrupted is some ways.
04605                // We can not get to the actual type of the data
04606                // let's assume it is NOT a string.
04607                return kFALSE;
04608             }
04609             if (elem->GetNewType()== TStreamerInfo::kOffsetL +kChar_t) {
04610                // Check whether a specific element of the string is specified!
04611                if (fIndexes[code][fNdimensions[code]-1] != -1) return kFALSE;
04612                return kTRUE;
04613             }
04614             if ( elem->GetNewType()== TStreamerInfo::kCharStar) {
04615                // Check whether a specific element of the string is specified!
04616                if (fNdimensions[code] && fIndexes[code][fNdimensions[code]-1] != -1) return kFALSE;
04617                return kTRUE;
04618             }
04619             return kFALSE;
04620          } else {
04621             return kFALSE;
04622          }
04623       case kMethod:
04624          //TMethodCall *m = GetMethodCall(code);
04625          //TMethodCall::EReturnType r = m->ReturnType();
04626          return kFALSE;
04627       case kDataMember:
04628          info = GetLeafInfo(code);
04629          return info->IsString();
04630       default:
04631          return kFALSE;
04632    }
04633 }
04634 
04635 //______________________________________________________________________________
04636 char *TTreeFormula::PrintValue(Int_t mode) const
04637 {
04638 // Return value of variable as a string
04639 //
04640 //      mode = -2 : Print line with ***
04641 //      mode = -1 : Print column names
04642 //      mode = 0  : Print column values
04643 
04644    return PrintValue(mode,0);
04645 }
04646 
04647 //______________________________________________________________________________
04648 char *TTreeFormula::PrintValue(Int_t mode, Int_t instance, const char *decform) const
04649 {
04650 // Return value of variable as a string
04651 //
04652 //      mode = -2 : Print line with ***
04653 //      mode = -1 : Print column names
04654 //      mode = 0  : Print column values
04655 //  decform contains the requested format (with the same convention as printf).
04656 //
04657 
04658    const int kMAXLENGTH = 1024;
04659    static char value[kMAXLENGTH];
04660 
04661    if (mode == -2) {
04662       for (int i = 0; i < kMAXLENGTH-1; i++)
04663          value[i] = '*';
04664       value[kMAXLENGTH-1] = 0;
04665    } else if (mode == -1) {
04666       snprintf(value, kMAXLENGTH-1, "%s", GetTitle());
04667    } else if (mode == 0) {
04668       if ( (fNstring && fNval==0 && fNoper==1) ||
04669            (TestBit(kIsCharacter)) )
04670       {
04671          const char * val = 0;
04672          if (instance<fNdata[0]) {
04673             if (fLookupType[0]==kTreeMember) {
04674                val = (char*)GetLeafInfo(0)->GetValuePointer((TLeaf*)0x0,instance);
04675             } else {
04676                TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);
04677                TBranch *branch = leaf->GetBranch();
04678                Long64_t readentry = branch->GetTree()->GetReadEntry();
04679                R__LoadBranch(branch,readentry,fQuickLoad);
04680                if (fLookupType[0]==kDirect && fNoper==1) {
04681                   val = (const char*)leaf->GetValuePointer();
04682                } else {
04683                   val = ((TTreeFormula*)this)->EvalStringInstance(instance);
04684                }
04685             }
04686          }
04687          if (val) {
04688             strlcpy(value, val, kMAXLENGTH);
04689          } else {
04690             value[0] = '\0';
04691          }
04692          value[kMAXLENGTH-1] = 0;
04693       } else {
04694          //NOTE: This is terrible form ... but is forced upon us by the fact that we can not
04695          //use the mutable keyword AND we should keep PrintValue const.
04696          Int_t real_instance = ((TTreeFormula*)this)->GetRealInstance(instance,-1);
04697          if (real_instance<fNdata[0]) {
04698             Ssiz_t len = strlen(decform);
04699             Char_t outputSizeLevel = 1; 
04700             char *expo = 0;
04701             if (len>2) {
04702                switch (decform[len-2]) {
04703                   case 'l':
04704                   case 'L': {
04705                      outputSizeLevel = 2; 
04706                      if (len>3 && tolower(decform[len-3])=='l') {
04707                         outputSizeLevel = 3;
04708                      }
04709                      break;
04710                   }
04711                   case 'h': outputSizeLevel = 0; break;
04712                }
04713             }
04714             switch(decform[len-1]) {
04715                case 'c':
04716                case 'd':
04717                case 'i':
04718                { 
04719                   switch (outputSizeLevel) {
04720                      case 0:  snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Short_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
04721                      case 2:  snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Long_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
04722                      case 3:  snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Long64_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
04723                      case 1:
04724                      default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Int_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
04725                   }
04726                   break;
04727                }
04728                case 'o': 
04729                case 'x':
04730                case 'X':
04731                case 'u':
04732                { 
04733                   switch (outputSizeLevel) {
04734                      case 0:  snprintf(value,kMAXLENGTH,Form("%%%s",decform),(UShort_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
04735                      case 2:  snprintf(value,kMAXLENGTH,Form("%%%s",decform),(ULong_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
04736                      case 3:  snprintf(value,kMAXLENGTH,Form("%%%s",decform),(ULong64_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
04737                      case 1:
04738                      default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(UInt_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
04739                   }
04740                   break;
04741                }
04742                case 'f':
04743                case 'e':
04744                case 'E':
04745                case 'g':
04746                case 'G':
04747                {
04748                   switch (outputSizeLevel) {
04749                      case 2:  snprintf(value,kMAXLENGTH,Form("%%%s",decform),(long double)((TTreeFormula*)this)->EvalInstance(instance)); break;
04750                      case 1:
04751                      default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),((TTreeFormula*)this)->EvalInstance(instance)); break;
04752                   }
04753                   expo = strchr(value,'e');
04754                   break;
04755                }
04756                default:
04757                   snprintf(value,kMAXLENGTH,Form("%%%sg",decform),((TTreeFormula*)this)->EvalInstance(instance));
04758                   expo = strchr(value,'e');
04759             }
04760             if (expo) {
04761                // If there is an exponent we may be longer than planned.
04762                // so let's trim off the excess precission!
04763                UInt_t declen = atoi(decform);
04764                if (strlen(value)>declen) {
04765                   UInt_t off = strlen(value)-declen;
04766                   char *start = expo - off;
04767                   UInt_t vlen = strlen(expo);
04768                   for(UInt_t z=0;z<=vlen;++z) {
04769                      start[z] = expo[z];
04770                   }
04771                   //strcpy(expo-off,expo);
04772                }
04773             }
04774          } else {
04775             if (isalpha(decform[strlen(decform)-1])) {
04776                TString short_decform(decform);
04777                short_decform.Remove(short_decform.Length()-1);
04778                snprintf(value,kMAXLENGTH,Form(" %%%sc",short_decform.Data()),' ');               
04779             } else {
04780                snprintf(value,kMAXLENGTH,Form(" %%%sc",decform),' ');
04781             }
04782             
04783          }
04784       }
04785    }
04786    return &value[0];
04787 }
04788 
04789 //______________________________________________________________________________
04790 void TTreeFormula::ResetLoading()
04791 {
04792    // Tell the formula that we are going to request a new entry.
04793 
04794    fNeedLoading = kTRUE;
04795    fDidBooleanOptimization = kFALSE;
04796 
04797    for(Int_t i=0; i<fNcodes; ++i) {
04798       UInt_t max_dim = fNdimensions[i];
04799       for(UInt_t dim=0; dim<max_dim ;++dim) {
04800          if (fVarIndexes[i][dim]) {
04801             fVarIndexes[i][dim]->ResetLoading();
04802          }
04803       }
04804    }
04805    Int_t n = fAliases.GetLast();
04806    if ( fNoper < n ) {
04807       n = fNoper;
04808    }
04809    for(Int_t k=0; k <= n; ++k) {
04810       TTreeFormula *f = static_cast<TTreeFormula*>(fAliases.UncheckedAt(k));
04811       if (f) {
04812          f->ResetLoading();
04813       }
04814    }
04815 }
04816 
04817 //______________________________________________________________________________
04818 void TTreeFormula::SetAxis(TAxis *axis)
04819 {
04820    // Set the axis (in particular get the type).
04821 
04822    if (!axis) {fAxis = 0; return;}
04823    if (TestBit(kIsCharacter)) {
04824       fAxis = axis;
04825       if (fNoper==1 && GetAction(0)==kAliasString){
04826          TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
04827          R__ASSERT(subform);
04828          subform->SetAxis(axis);
04829       } else if (fNoper==2 && GetAction(0)==kAlternateString){
04830          TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
04831          R__ASSERT(subform);
04832          subform->SetAxis(axis);
04833       }
04834    }
04835    if (IsInteger()) axis->SetBit(TAxis::kIsInteger);
04836 }
04837 
04838 //______________________________________________________________________________
04839 void TTreeFormula::Streamer(TBuffer &R__b)
04840 {
04841    // Stream an object of class TTreeFormula.
04842 
04843    if (R__b.IsReading()) {
04844       UInt_t R__s, R__c;
04845       Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
04846       if (R__v > 2) {
04847          R__b.ReadClassBuffer(TTreeFormula::Class(), this, R__v, R__s, R__c);
04848          return;
04849       }
04850       //====process old versions before automatic schema evolution
04851       TFormula::Streamer(R__b);
04852       R__b >> fTree;
04853       R__b >> fNcodes;
04854       R__b.ReadFastArray(fCodes, fNcodes);
04855       R__b >> fMultiplicity;
04856       Int_t instance;
04857       R__b >> instance; //data member removed
04858       R__b >> fNindex;
04859       if (fNindex) {
04860          fLookupType = new Int_t[fNindex];
04861          R__b.ReadFastArray(fLookupType, fNindex);
04862       }
04863       fMethods.Streamer(R__b);
04864       //====end of old versions
04865 
04866    } else {
04867       R__b.WriteClassBuffer(TTreeFormula::Class(),this);
04868    }
04869 }
04870 
04871 //______________________________________________________________________________
04872 Bool_t TTreeFormula::StringToNumber(Int_t oper)
04873 {
04874    // Try to 'demote' a string into an array bytes.  If this is not possible,
04875    // return false.
04876    
04877    Int_t code = GetActionParam(oper);
04878    if (GetAction(oper)==kDefinedString && fLookupType[code]==kDirect) {
04879       if (oper>0 && GetAction(oper-1)==kJump) {
04880          // We are the second hand of a ternary operator, let's not do the fixing.
04881          return kFALSE;
04882       }
04883       TLeaf *leaf = (TLeaf*)fLeaves.At(code);
04884       if (leaf &&  (leaf->InheritsFrom(TLeafC::Class()) || leaf->InheritsFrom(TLeafB::Class()) ) ) {
04885          SetAction(oper, kDefinedVariable, code );
04886          fNval++;
04887          fNstring--;
04888          return kTRUE;
04889       }
04890    }
04891    return kFALSE;
04892 }
04893 
04894 
04895 //______________________________________________________________________________
04896 void TTreeFormula::UpdateFormulaLeaves()
04897 {
04898    // this function is called TTreePlayer::UpdateFormulaLeaves, itself
04899    // called by TChain::LoadTree when a new Tree is loaded.
04900    // Because Trees in a TChain may have a different list of leaves, one
04901    // must update the leaves numbers in the TTreeFormula used by the TreePlayer.
04902 
04903    // A safer alternative would be to recompile the whole thing .... However
04904    // currently compile HAS TO be called from the constructor!
04905 
04906    TString names(kMaxLen);
04907    Int_t nleaves = fLeafNames.GetEntriesFast();
04908    ResetBit( kMissingLeaf );
04909    for (Int_t i=0;i<nleaves;i++) {
04910       if (!fTree) break;
04911       if (!fLeafNames[i]) continue;
04912       names.Form("%s/%s",fLeafNames[i]->GetTitle(),fLeafNames[i]->GetName());
04913       TLeaf *leaf = fTree->GetLeaf(names);
04914       fLeaves[i] = leaf;
04915       if (fBranches[i] && leaf) {
04916          fBranches[i]=leaf->GetBranch();
04917          // Since sometimes we might no read all the branches for all the entries, we 
04918          // might sometimes only read the branch count and thus reset the colleciton
04919          // but might not read the data branches, to insure that a subsequent read 
04920          // from TTreeFormula will properly load the data branches even if fQuickLoad is true,
04921          // we reset the entry of all branches in the TTree.
04922          ((TBranch*)fBranches[i])->ResetReadEntry();
04923       }
04924       if (leaf==0) SetBit( kMissingLeaf );
04925    }
04926    for (Int_t j=0; j<kMAXCODES; j++) {
04927       for (Int_t k = 0; k<kMAXFORMDIM; k++) {
04928          if (fVarIndexes[j][k]) {
04929             fVarIndexes[j][k]->UpdateFormulaLeaves();
04930          }
04931       }
04932       if (fLookupType[j]==kDataMember || fLookupType[j]==kTreeMember) GetLeafInfo(j)->Update();
04933       if (j<fNval && fCodes[j]<0) {
04934          TCutG *gcut = (TCutG*)fExternalCuts.At(j);
04935          if (gcut) {
04936            TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
04937            TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
04938            if (fx) fx->UpdateFormulaLeaves();
04939            if (fy) fy->UpdateFormulaLeaves();
04940          }
04941       }
04942    }
04943    for(Int_t k=0;k<fNoper;k++) {
04944       const Int_t oper = GetOper()[k];
04945       switch(oper >> kTFOperShift) {
04946          case kAlias:
04947          case kAliasString:
04948          case kAlternate:
04949          case kAlternateString:
04950          case kMinIf:
04951          case kMaxIf:
04952          {
04953             TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(k));
04954             R__ASSERT(subform);
04955             subform->UpdateFormulaLeaves();
04956             break;
04957          }
04958          case kDefinedVariable:
04959          {
04960             Int_t code = GetActionParam(k);
04961             if (fCodes[code]==0) switch(fLookupType[code]) {
04962                case kLengthFunc:
04963                case kSum:
04964                case kMin:
04965                case kMax:
04966                {
04967                   TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(k));
04968                   R__ASSERT(subform);
04969                   subform->UpdateFormulaLeaves();
04970                   break;
04971                }
04972                default:
04973                   break;
04974             }
04975          }
04976          default:
04977             break;
04978       }
04979    }
04980 }
04981 
04982 //______________________________________________________________________________
04983 void TTreeFormula::ResetDimensions() {
04984    // Populate the TTreeFormulaManager with the dimension information.
04985 
04986    Int_t i,k;
04987 
04988    // Now that we saw all the expressions and variables AND that
04989    // we know whether arrays of chars are treated as string or
04990    // not, we can properly setup the dimensions.
04991    TIter next(fDimensionSetup);
04992    Int_t last_code = -1;
04993    Int_t virt_dim = 0;
04994    for(TDimensionInfo * info; (info = (TDimensionInfo*)next()); ) {
04995       if (last_code!=info->fCode) {
04996          // We know that the list is ordered by code number then by
04997          // dimension.  Thus a different code means that we need to
04998          // restart at the lowest dimensions.
04999          virt_dim = 0;
05000          last_code = info->fCode;
05001          fNdimensions[last_code] = 0;
05002       }
05003 
05004       if (GetAction(info->fOper)==kDefinedString) {
05005 
05006          // We have a string used as a string (and not an array of number)
05007          // We need to determine which is the last dimension and skip it.
05008          TDimensionInfo *nextinfo = (TDimensionInfo*)next();
05009          while(nextinfo && nextinfo->fCode==info->fCode) {
05010             DefineDimensions(info->fCode,info->fSize, info->fMultiDim, virt_dim);
05011             nextinfo = (TDimensionInfo*)next();
05012          }
05013          if (!nextinfo) break;
05014 
05015          info = nextinfo;
05016          virt_dim = 0;
05017          last_code = info->fCode;
05018          fNdimensions[last_code] = 0;
05019 
05020          info->fSize = 1; // Maybe this should actually do nothing!
05021       }
05022 
05023 
05024       DefineDimensions(info->fCode,info->fSize, info->fMultiDim, virt_dim);
05025    }
05026 
05027    fMultiplicity = 0;
05028    for(i=0;i<fNoper;i++) {
05029       Int_t action = GetAction(i);
05030 
05031       if (action==kMinIf || action==kMaxIf) {
05032          // Skip/Ignore the 2nd args
05033          ++i;
05034          continue;
05035       }
05036       if (action==kAlias || action==kAliasString) {
05037          TTreeFormula *subform = static_cast<TTreeFormula*>(fAliases.UncheckedAt(i));
05038          R__ASSERT(subform);
05039          switch(subform->GetMultiplicity()) {
05040             case 0: break;
05041             case 1: fMultiplicity = 1; break;
05042             case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
05043          }
05044          fManager->Add(subform);
05045          // since we are addint to this manager 'subform->ResetDimensions();'
05046          // will be called a little latter
05047          continue;
05048       }
05049       if (action==kDefinedString) {
05050       //if (fOper[i] >= 105000 && fOper[i]<110000) {
05051          // We have a string used as a string
05052 
05053          // This dormant portion of code would be used if (when?) we allow the histogramming
05054          // of the integral content (as opposed to the string content) of strings
05055          // held in a variable size container delimited by a null (as opposed to
05056          // a fixed size container or variable size container whose size is controlled
05057          // by a variable).  In GetNdata, we will then use strlen to grab the current length.
05058          //fCumulSizes[i][fNdimensions[i]-1] = 1;
05059          //fUsedSizes[fNdimensions[i]-1] = -TMath::Abs(fUsedSizes[fNdimensions[i]-1]);
05060          //fUsedSizes[0] = - TMath::Abs( fUsedSizes[0]);
05061 
05062          //continue;
05063       }
05064    }
05065 
05066    for (i=0;i<fNcodes;i++) {
05067       if (fCodes[i] < 0) {
05068          TCutG *gcut = (TCutG*)fExternalCuts.At(i);
05069          if (!gcut) continue;
05070          TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
05071          TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
05072 
05073          if (fx) {
05074             switch(fx->GetMultiplicity()) {
05075                case 0: break;
05076                case 1: fMultiplicity = 1; break;
05077                case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
05078             }
05079             fManager->Add(fx);
05080          }
05081          if (fy) {
05082             switch(fy->GetMultiplicity()) {
05083                case 0: break;
05084                case 1: fMultiplicity = 1; break;
05085                case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
05086             }
05087             fManager->Add(fy);
05088          }
05089 
05090          continue;
05091       }
05092 
05093       if (fLookupType[i]==kIteration) {
05094           fMultiplicity = 1;
05095           continue;
05096       }
05097 
05098       TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(i);
05099       if (!leaf) continue;
05100 
05101       // Reminder of the meaning of fMultiplicity:
05102       //  -1: Only one or 0 element per entry but contains variable length
05103       //      -array! (Only used for TTreeFormulaManager)
05104       //   0: Only one element per entry, no variable length array
05105       //   1: loop over the elements of a variable length array
05106       //   2: loop over elements of fixed length array (nData is the same for all entry)
05107 
05108       if (leaf->GetLeafCount()) {
05109          // We assume only one possible variable length dimension (the left most)
05110          fMultiplicity = 1;
05111       } else if (fLookupType[i]==kDataMember) {
05112          TFormLeafInfo * leafinfo = GetLeafInfo(i);
05113          TStreamerElement * elem = leafinfo->fElement;
05114          if (fMultiplicity!=1) {
05115             if (leafinfo->HasCounter() ) fMultiplicity = 1;
05116             else if (elem && elem->GetArrayDim()>0) fMultiplicity = 2;
05117             else if (leaf->GetLenStatic()>1) fMultiplicity = 2;
05118          }
05119       } else {
05120          if (leaf->GetLenStatic()>1 && fMultiplicity!=1) fMultiplicity = 2;
05121       }
05122       if (fMultiplicity!=1) {
05123          // If the leaf belongs to a friend tree which has an index, we might
05124          // be in the case where some entry do not exist.
05125             
05126          TTree *realtree = fTree ? fTree->GetTree() : 0;
05127          TTree *tleaf = leaf->GetBranch()->GetTree();
05128          if (tleaf && tleaf != realtree && tleaf->GetTreeIndex()) {
05129             // Reset the multiplicity if we have a friend tree with an index.
05130             fMultiplicity = 1;
05131          }
05132       }
05133 
05134       Int_t virt_dim2 = 0;
05135       for (k = 0; k < fNdimensions[i]; k++) {
05136          // At this point fCumulSizes[i][k] actually contain the physical
05137          // dimension of the k-th dimensions.
05138          if ( (fCumulSizes[i][k]>=0) && (fIndexes[i][k] >= fCumulSizes[i][k]) ) {
05139             // unreacheable element requested:
05140             fManager->CancelDimension(virt_dim2); // fCumulUsedSizes[virt_dim2] = 0;
05141          }
05142          if ( fIndexes[i][k] < 0 ) virt_dim2++;
05143          fFixedSizes[i][k] = fCumulSizes[i][k];
05144       }
05145 
05146       // Add up the cumulative size
05147       for (k = fNdimensions[i]; (k > 0); k--) {
05148          // NOTE: When support for inside variable dimension is added this
05149          // will become inacurate (since one of the value in the middle of the chain
05150          // is unknown until GetNdata is called.
05151          fCumulSizes[i][k-1] *= TMath::Abs(fCumulSizes[i][k]);
05152       }
05153       // NOTE: We assume that the inside variable dimensions are dictated by the
05154       // first index.
05155       if (fCumulSizes[i][0]>0) fNdata[i] = fCumulSizes[i][0];
05156 
05157       //for (k = 0; k<kMAXFORMDIM; k++) {
05158       //   if (fVarIndexes[i][k]) fManager->Add(fVarIndexes[i][k]);
05159       //}
05160 
05161    }
05162 }
05163 
05164 //______________________________________________________________________________
05165 void TTreeFormula::LoadBranches()
05166 {
05167    // Make sure that all the branches have been loaded properly.
05168 
05169    Int_t i;
05170    for (i=0; i<fNoper ; ++i) {
05171       TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(i);
05172       if (leaf==0) continue;
05173 
05174       TBranch *br = leaf->GetBranch();
05175       Long64_t treeEntry = br->GetTree()->GetReadEntry();
05176       R__LoadBranch(br,treeEntry,kTRUE);
05177 
05178       TTreeFormula *alias = (TTreeFormula*)fAliases.UncheckedAt(i);
05179       if (alias) alias->LoadBranches();
05180 
05181       Int_t max_dim = fNdimensions[i];
05182       for (Int_t dim = 0; dim < max_dim; ++dim) {
05183          if (fVarIndexes[i][dim]) fVarIndexes[i][dim]->LoadBranches();
05184       }
05185    }
05186 }
05187 
05188 //______________________________________________________________________________
05189 Bool_t TTreeFormula::LoadCurrentDim() {
05190 
05191    // Calculate the actual dimension for the current entry.
05192 
05193    Int_t size;
05194    Bool_t outofbounds = kFALSE;
05195 
05196    for (Int_t i=0;i<fNcodes;i++) {
05197       if (fCodes[i] < 0) continue;
05198 
05199       // NOTE: Currently only the leafcount can indicates a dimension that
05200       // is physically variable.  So only the left-most dimension is variable.
05201       // When an API is introduced to be able to determine a variable inside dimensions
05202       // one would need to add a way to recalculate the values of fCumulSizes for this
05203       // leaf.  This would probably require the addition of a new data member
05204       // fSizes[kMAXCODES][kMAXFORMDIM];
05205       // Also note that EvalInstance expect all the values (but the very first one)
05206       // of fCumulSizes to be positive.  So indicating that a physical dimension is
05207       // variable (expected for the first one) can NOT be done via negative values of
05208       // fCumulSizes.
05209 
05210       TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(i);
05211       if (!leaf) {
05212          switch(fLookupType[i]) {
05213             case kDirect: 
05214             case kMethod:
05215             case kTreeMember:
05216             case kDataMember:
05217                fNdata[i] = 0;
05218                outofbounds = kTRUE;
05219          }
05220          continue;
05221       }
05222 
05223       TTree *realtree = fTree->GetTree();
05224       TTree *tleaf = leaf->GetBranch()->GetTree();
05225       if (tleaf && tleaf != realtree && tleaf->GetTreeIndex()) {
05226          if (tleaf->GetReadEntry()==-1) {
05227             fNdata[i] = 0;
05228             outofbounds = kTRUE;
05229             continue;
05230          } else {
05231             fNdata[i] = fCumulSizes[i][0];
05232          }
05233       }
05234       Bool_t hasBranchCount2 = kFALSE;
05235       if (leaf->GetLeafCount()) {
05236          TLeaf* leafcount = leaf->GetLeafCount();
05237          TBranch *branchcount = leafcount->GetBranch();
05238          TFormLeafInfo * info = 0;
05239          if (leaf->IsA() == TLeafElement::Class()) {
05240             //if branchcount address not yet set, GetEntry will set the address
05241             // read branchcount value
05242             Long64_t readentry = leaf->GetBranch()->GetTree()->GetReadEntry();
05243             if (readentry==-1) readentry=0;
05244             if (!branchcount->GetAddress()) {
05245                R__LoadBranch(branchcount, readentry, fQuickLoad);
05246             } else {
05247                // Since we do not read the full branch let's reset the read entry number
05248                // so that a subsequent read from TTreeFormula will properly load the full
05249                // object even if fQuickLoad is true.
05250                branchcount->TBranch::GetEntry(readentry);
05251                branchcount->ResetReadEntry();
05252             }
05253 
05254             size = ((TBranchElement*)branchcount)->GetNdata();
05255             // Reading the size as above is correct only when the branchcount
05256             // is of streamer type kCounter which require the underlying data
05257             // member to be signed integral type.
05258 
05259             TBranchElement* branch = (TBranchElement*) leaf->GetBranch();
05260 
05261             // NOTE: could be sped up
05262             if (fHasMultipleVarDim[i]) {// info && info->GetVarDim()>=0) {
05263                info = (TFormLeafInfo* )fDataMembers.At(i);
05264                if (branch->GetBranchCount2()) R__LoadBranch(branch->GetBranchCount2(),readentry,fQuickLoad);
05265                else R__LoadBranch(branch,readentry,fQuickLoad);
05266 
05267                // Here we need to add the code to take in consideration the
05268                // double variable length
05269                // We fill up the array of sizes in the TLeafInfo:
05270                info->LoadSizes(branch);
05271                hasBranchCount2 = kTRUE;
05272                if (info->GetVirtVarDim()>=0) info->UpdateSizes(fManager->fVarDims[info->GetVirtVarDim()]);
05273 
05274                // Refresh the fCumulSizes[i] to have '1' for the
05275                // double variable dimensions
05276                Int_t vdim = info->GetVarDim();
05277                fCumulSizes[i][vdim] =  fCumulSizes[i][vdim+1];
05278                for(Int_t k=vdim -1; k>=0; k--) {
05279                   fCumulSizes[i][k] = fCumulSizes[i][k+1]*fFixedSizes[i][k];
05280                }
05281                // Update fCumulUsedSizes
05282                // UpdateMultiVarSizes(vdim,info,i)
05283                //Int_t fixed = fCumulSizes[i][vdim+1];
05284                //for(Int_t k=vdim - 1; k>=0; k++) {
05285                //   Int_t fixed *= fFixedSizes[i][k];
05286                //   for(Int_t l=0;l<size; l++) {
05287                //     fCumulSizes[i][k] += info->GetSize(l) * fixed;
05288                //}
05289             }
05290          } else {
05291             Long64_t readentry = leaf->GetBranch()->GetTree()->GetReadEntry();
05292             if (readentry==-1) readentry=0;
05293             R__LoadBranch(branchcount,readentry,fQuickLoad);
05294             size = leaf->GetLen() / leaf->GetLenStatic();
05295          }
05296          if (hasBranchCount2) {
05297             // We assume that fCumulSizes[i][1] contains the product of the fixed sizes
05298             fNdata[i] = fCumulSizes[i][1] * ((TFormLeafInfo *)fDataMembers.At(i))->GetSumOfSizes();
05299          } else {
05300             fNdata[i] = size * fCumulSizes[i][1];
05301          }
05302          if (fIndexes[i][0]==-1) {
05303             // Case where the index is not specified AND the 1st dimension has a variable
05304             // size.
05305             if (fManager->fUsedSizes[0]==1 || (size<fManager->fUsedSizes[0]) ) fManager->fUsedSizes[0] = size;
05306             if (info && fIndexes[i][info->GetVarDim()]>=0) {
05307                for(Int_t j=0; j<size; j++) {
05308                   if (fIndexes[i][info->GetVarDim()] >= info->GetSize(j)) {
05309                      info->SetSize(j,0);
05310                      if (size>fManager->fCumulUsedVarDims->GetSize()) fManager->fCumulUsedVarDims->Set(size);
05311                      fManager->fCumulUsedVarDims->AddAt(-1,j);
05312                   } else if (fIndexes[i][info->GetVarDim()]>=0) {
05313                      // There is an index and it is not too large
05314                      info->SetSize(j,1);
05315                      if (size>fManager->fCumulUsedVarDims->GetSize()) fManager->fCumulUsedVarDims->Set(size);
05316                      fManager->fCumulUsedVarDims->AddAt(1,j);
05317                   }
05318                }
05319             }
05320          } else if (fIndexes[i][0] >= size) {
05321             // unreacheable element requested:
05322             fManager->fUsedSizes[0] = 0;
05323             fNdata[i] = 0;
05324             outofbounds = kTRUE;
05325          } else if (hasBranchCount2) {
05326             TFormLeafInfo *info2;
05327             info2 = (TFormLeafInfo *)fDataMembers.At(i);
05328             if (fIndexes[i][0]<0
05329                 || fIndexes[i][info2->GetVarDim()] >= info2->GetSize(fIndexes[i][0])) {
05330                // unreacheable element requested:
05331                fManager->fUsedSizes[0] = 0;
05332                fNdata[i] = 0;
05333                outofbounds = kTRUE;
05334             }
05335          }
05336       } else if (fLookupType[i]==kDataMember) {
05337          TFormLeafInfo *leafinfo = (TFormLeafInfo*)fDataMembers.UncheckedAt(i);
05338          if (leafinfo->HasCounter()) {
05339             TBranch *branch = leaf->GetBranch();
05340             Long64_t readentry = branch->GetTree()->GetReadEntry();
05341             if (readentry==-1) readentry=0;
05342             R__LoadBranch(branch,readentry,fQuickLoad);
05343             size = (Int_t) leafinfo->GetCounterValue(leaf);
05344             if (fIndexes[i][0]==-1) {
05345                // Case where the index is not specified AND the 1st dimension has a variable
05346                // size.
05347                if (fManager->fUsedSizes[0]==1 || (size<fManager->fUsedSizes[0]) ) {
05348                   fManager->fUsedSizes[0] = size;
05349                }
05350             } else if (fIndexes[i][0] >= size) {
05351                // unreacheable element requested:
05352                fManager->fUsedSizes[0] = 0;
05353                fNdata[i] = 0;
05354                outofbounds = kTRUE;
05355             } else {
05356                fNdata[i] = size*fCumulSizes[i][1];
05357             }
05358             Int_t vdim = leafinfo->GetVarDim();
05359             if (vdim>=0) {
05360                // Here we need to add the code to take in consideration the
05361                // double variable length
05362                // We fill up the array of sizes in the TLeafInfo:
05363                // here we can assume that branch is a TBranch element because the other style does NOT support this type
05364                // of complexity.
05365                leafinfo->LoadSizes(branch);
05366                hasBranchCount2 = kTRUE;
05367                if (fIndexes[i][0]==-1&&fIndexes[i][vdim] >= 0) {
05368                   for(int z=0; z<size; ++z) {
05369                      if (fIndexes[i][vdim] >= leafinfo->GetSize(z)) {
05370                         leafinfo->SetSize(z,0);
05371                         // --fManager->fUsedSizes[0];
05372                      } else if (fIndexes[i][vdim] >= 0 ) {
05373                         leafinfo->SetSize(z,1);
05374                      }
05375                   }
05376                }
05377                leafinfo->UpdateSizes(fManager->fVarDims[vdim]);
05378 
05379                // Refresh the fCumulSizes[i] to have '1' for the
05380                // double variable dimensions
05381                fCumulSizes[i][vdim] =  fCumulSizes[i][vdim+1];
05382                for(Int_t k=vdim -1; k>=0; k--) {
05383                   fCumulSizes[i][k] = fCumulSizes[i][k+1]*fFixedSizes[i][k];
05384                }
05385                fNdata[i] = fCumulSizes[i][1] * leafinfo->GetSumOfSizes();
05386             } else {
05387                fNdata[i] = size * fCumulSizes[i][1];
05388             }
05389          } else if (leafinfo->GetMultiplicity()==-1) {
05390             TBranch *branch = leaf->GetBranch();
05391             Long64_t readentry = branch->GetTree()->GetReadEntry();
05392             if (readentry==-1) readentry=0;
05393             R__LoadBranch(branch,readentry,fQuickLoad);
05394             if (leafinfo->GetNdata(leaf)==0) {
05395                outofbounds = kTRUE;
05396             }
05397          }
05398       }
05399       // However we allow several dimensions that virtually vary via the size of their
05400       // index variables.  So we have code to recalculate fCumulUsedSizes.
05401       Int_t index;
05402       TFormLeafInfo * info = 0;
05403       if (fLookupType[i]!=kDirect) {
05404          info = (TFormLeafInfo *)fDataMembers.At(i);
05405       }
05406       for(Int_t k=0, virt_dim=0; k < fNdimensions[i]; k++) {
05407          if (fIndexes[i][k]<0) {
05408             if (fIndexes[i][k]==-2 && fManager->fVirtUsedSizes[virt_dim]<0) {
05409 
05410                // if fVirtUsedSize[virt_dim] is positive then VarIndexes[i][k]->GetNdata()
05411                // is always the same and has already been factored in fUsedSize[virt_dim]
05412                index = fVarIndexes[i][k]->GetNdata();
05413                if (index==1) {
05414                   // We could either have a variable size array which is currently of size one
05415                   // or a single element that might or not might not be present (and is currently present!)
05416                   if (fVarIndexes[i][k]->GetManager()->GetMultiplicity()==1) {
05417                      if (index<fManager->fUsedSizes[virt_dim]) fManager->fUsedSizes[virt_dim] = index;
05418                   }
05419 
05420                } else if (fManager->fUsedSizes[virt_dim]==-fManager->fVirtUsedSizes[virt_dim] ||
05421                           index<fManager->fUsedSizes[virt_dim]) {
05422                   fManager->fUsedSizes[virt_dim] = index;
05423                }
05424 
05425             } else if (hasBranchCount2 && info && k==info->GetVarDim()) {
05426                // NOTE: We assume the indexing of variable sizes on the first index!
05427                if (fIndexes[i][0]>=0) {
05428                   index = info->GetSize(fIndexes[i][0]);
05429                   if (fManager->fUsedSizes[virt_dim]==1 || (index!=1 && index<fManager->fUsedSizes[virt_dim]) )
05430                      fManager->fUsedSizes[virt_dim] = index;
05431                }
05432             }
05433             virt_dim++;
05434          } else if (hasBranchCount2 && info && k==info->GetVarDim()) {
05435 
05436             // nothing to do, at some point I thought this might be useful:
05437             // if (fIndexes[i][k]>=0) {
05438             //    index = info->GetSize(fIndexes[i][k]);
05439             //    if (fManager->fUsedSizes[virt_dim]==1 || (index!=1 && index<fManager->fUsedSizes[virt_dim]) )
05440             //      fManager->fUsedSizes[virt_dim] = index;
05441             //    virt_dim++;
05442             // }
05443 
05444          }
05445       }
05446    }
05447    return ! outofbounds;
05448 
05449 
05450 
05451 }
05452 
05453 void TTreeFormula::Convert(UInt_t oldversion)
05454 {
05455    // Convert the fOper of a TTTreeFormula version fromVersion to the current in memory version
05456 
05457    enum { kOldAlias           = /*TFormula::kVariable*/ 100000+10000+1,
05458           kOldAliasString     = kOldAlias+1,
05459           kOldAlternate       = kOldAlias+2,
05460           kOldAlternateString = kOldAliasString+2
05461    };
05462 
05463    for (int k=0; k<fNoper; k++) {
05464       // First hide from TFormula convertion
05465 
05466       Int_t action = GetOper()[k];
05467 
05468       switch (action) {
05469 
05470          case kOldAlias:            GetOper()[k] = -kOldAlias; break;
05471          case kOldAliasString:      GetOper()[k] = -kOldAliasString; break;
05472          case kOldAlternate:        GetOper()[k] = -kOldAlternate; break;
05473          case kOldAlternateString:  GetOper()[k] = -kOldAlternateString; break;
05474       }
05475    }
05476 
05477    TFormula::Convert(oldversion);
05478 
05479    for (int i=0,offset=0; i<fNoper; i++) {
05480       Int_t action = GetOper()[i+offset];
05481 
05482       switch (action) {
05483          case -kOldAlias:            SetAction(i, kAlias, 0); break;
05484          case -kOldAliasString:      SetAction(i, kAliasString, 0); break;
05485          case -kOldAlternate:        SetAction(i, kAlternate, 0); break;
05486          case -kOldAlternateString:  SetAction(i, kAlternateString, 0); break;
05487       }
05488    }
05489 
05490 }
05491 
05492 //______________________________________________________________________________
05493 Bool_t TTreeFormula::SwitchToFormLeafInfo(Int_t code)
05494 {
05495    // Convert the underlying lookup method from the direct technique
05496    // (dereferencing the address held by the branch) to the method using
05497    // TFormLeafInfo.  This is in particular usefull in the case where we
05498    // need to append an additional TFormLeafInfo (for example to call a
05499    // method).
05500    // Return false if the switch was unsuccessfull (basically in the
05501    // case of an old style split tree).
05502 
05503    TFormLeafInfo *last = 0;
05504    TLeaf *leaf = (TLeaf*)fLeaves.At(code);
05505    if (!leaf) return kFALSE;
05506 
05507    if (fLookupType[code]==kDirect) {
05508       if (leaf->InheritsFrom(TLeafElement::Class())) {
05509          TBranchElement * br = (TBranchElement*)leaf->GetBranch();
05510          if (br->GetType()==31) {
05511             // sub branch of a TClonesArray
05512             TStreamerInfo *info = br->GetInfo();
05513             TClass* cl = info->GetClass();
05514             TStreamerElement *element = (TStreamerElement *)info->GetElems()[br->GetID()];
05515             TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(cl, 0, element, kTRUE);
05516             Int_t offset;
05517             info->GetStreamerElement(element->GetName(),offset);
05518             clonesinfo->fNext = new TFormLeafInfo(cl,offset+br->GetOffset(),element);
05519             last = clonesinfo->fNext;
05520             fDataMembers.AddAtAndExpand(clonesinfo,code);
05521             fLookupType[code]=kDataMember;
05522 
05523          } else if (br->GetType()==41) {
05524             // sub branch of a Collection
05525 
05526             TBranchElement *count = br->GetBranchCount();
05527             TFormLeafInfo* collectioninfo;
05528             if ( count->GetID() >= 0 ) {
05529                TStreamerElement *collectionElement =
05530                   (TStreamerElement *)count->GetInfo()->GetElems()[count->GetID()];
05531                TClass *collectionCl = collectionElement->GetClassPointer();
05532 
05533                collectioninfo =
05534                   new TFormLeafInfoCollection(collectionCl, 0, collectionElement, kTRUE);
05535             } else {
05536                TClass *collectionCl = TClass::GetClass(count->GetClassName());
05537                collectioninfo =
05538                   new TFormLeafInfoCollection(collectionCl, 0, collectionCl, kTRUE);
05539             }
05540 
05541             TStreamerInfo *info = br->GetInfo();
05542             TClass* cl = info->GetClass();
05543             TStreamerElement *element = (TStreamerElement *)info->GetElems()[br->GetID()];
05544             Int_t offset;
05545             info->GetStreamerElement(element->GetName(),offset);
05546             collectioninfo->fNext = new TFormLeafInfo(cl,offset+br->GetOffset(),element);
05547             last = collectioninfo->fNext;
05548             fDataMembers.AddAtAndExpand(collectioninfo,code);
05549             fLookupType[code]=kDataMember;
05550 
05551          } else if (br->GetID()<0) { 
05552             return kFALSE;
05553          } else {
05554             last = new TFormLeafInfoDirect(br);
05555             fDataMembers.AddAtAndExpand(last,code);
05556             fLookupType[code]=kDataMember;
05557          }
05558       } else {
05559          //last = new TFormLeafInfoDirect(br);
05560          //fDataMembers.AddAtAndExpand(last,code);
05561          //fLookupType[code]=kDataMember;
05562          return kFALSE;
05563       }
05564    }
05565    return kTRUE;
05566 }

Generated on Tue Jul 5 15:43:02 2011 for ROOT_528-00b_version by  doxygen 1.5.1