diff --git a/cont/src/TEmulatedCollectionProxy.cxx b/cont/src/TEmulatedCollectionProxy.cxx index 39a3d3eaabec289a7f772367cce1e0d5ca6d665c..5a494df5922205a7c2b484ffc402872186e7f4d6 100644 --- a/cont/src/TEmulatedCollectionProxy.cxx +++ b/cont/src/TEmulatedCollectionProxy.cxx @@ -1,4 +1,4 @@ -// @(#)root/cont:$Name: $:$Id: TEmulatedCollectionProxy.cxx,v 1.7 2005/01/19 18:30:58 brun Exp $ +// @(#)root/cont:$Name: $:$Id: TEmulatedCollectionProxy.cxx,v 1.8 2005/03/10 22:26:15 rdm Exp $ // Author: Markus Frank 28/10/04 /************************************************************************* @@ -301,7 +301,7 @@ void* TEmulatedCollectionProxy::At(UInt_t idx) { if ( idx >= (s/fValDiff) ) { return 0; } - return idx<(c->size()/fValDiff) ? ((char*)&(*c->begin()))+idx*fValDiff : 0; + return idx<(s/fValDiff) ? ((char*)&(*c->begin()))+idx*fValDiff : 0; } Fatal("TEmulatedCollectionProxy","At> Logic error - no proxy object set."); return 0; diff --git a/hist/src/TFormula.cxx b/hist/src/TFormula.cxx index db8a987d383ab41c258652728587cd65f5736b0c..6fc6a837ace386352a8e920f308c6ddb68b6add1 100644 --- a/hist/src/TFormula.cxx +++ b/hist/src/TFormula.cxx @@ -1,4 +1,4 @@ -// @(#)root/hist:$Name: $:$Id: TFormula.cxx,v 1.90 2005/03/04 18:38:52 brun Exp $ +// @(#)root/hist:$Name: $:$Id: TFormula.cxx,v 1.91 2005/03/04 19:37:52 brun Exp $ // Author: Nicolas Brun 19/08/95 /************************************************************************* @@ -553,7 +553,7 @@ void TFormula::Analyze(const char *schain, Int_t &err, Int_t offset) //*-* 28 : strstr requires two arguments //*-* 29 : interpreted or compiled function have to return a numerical type //*-* 30 : Bad numerical expression -//*-* 31 : Variable exist but is not accessible +//*-* 31 : Part of the variable exist but some of it is not accessible or useable //*-* 40 : '(' is expected //*-* 41 : ')' is expected //*-* 42 : '[' is expected @@ -1838,7 +1838,7 @@ void TFormula::Analyze(const char *schain, Int_t &err, Int_t offset) case 29 : cout<<" TFormula can only call interpreted and compiled functions that return a numerical type: \n" <<chaine_error<<endl; break; case 30 : cout<<" Bad numerical expression : \""<<(const char*)chaine_error<<"\""<<endl; break; - case 31 : cout<<" The Variable : \""<<(const char*)chaine_error<<"\" exists but is not accessible"<<endl; break; + case 31 : cout<<" Part of the Variable : \""<<(const char*)chaine_error<<"\" exists but some of it is not accessible or useable"<<endl; break; case 40 : cout<<" '(' is expected"<<endl; break; case 41 : cout<<" ')' is expected"<<endl; break; case 42 : cout<<" '[' is expected"<<endl; break; diff --git a/io/src/TEmulatedCollectionProxy.cxx b/io/src/TEmulatedCollectionProxy.cxx index 39a3d3eaabec289a7f772367cce1e0d5ca6d665c..5a494df5922205a7c2b484ffc402872186e7f4d6 100644 --- a/io/src/TEmulatedCollectionProxy.cxx +++ b/io/src/TEmulatedCollectionProxy.cxx @@ -1,4 +1,4 @@ -// @(#)root/cont:$Name: $:$Id: TEmulatedCollectionProxy.cxx,v 1.7 2005/01/19 18:30:58 brun Exp $ +// @(#)root/cont:$Name: $:$Id: TEmulatedCollectionProxy.cxx,v 1.8 2005/03/10 22:26:15 rdm Exp $ // Author: Markus Frank 28/10/04 /************************************************************************* @@ -301,7 +301,7 @@ void* TEmulatedCollectionProxy::At(UInt_t idx) { if ( idx >= (s/fValDiff) ) { return 0; } - return idx<(c->size()/fValDiff) ? ((char*)&(*c->begin()))+idx*fValDiff : 0; + return idx<(s/fValDiff) ? ((char*)&(*c->begin()))+idx*fValDiff : 0; } Fatal("TEmulatedCollectionProxy","At> Logic error - no proxy object set."); return 0; diff --git a/test/dt_DrawTest.C b/test/dt_DrawTest.C index 258d0a3f7a8f7fde49a492481e0e30d56fed6dee..6ebc43f9f5b0ab6041a5f431ee7555367fea2727 100644 --- a/test/dt_DrawTest.C +++ b/test/dt_DrawTest.C @@ -56,7 +56,7 @@ void DrawMarks() { //_______________________________________________________________ -TDirectory* GenerateDrawHist(TTree *tree,int level = 2, int quietLevel = 0) +TDirectory* GenerateDrawHist(TTree *tree, int quietLevel = 0, int level = 3) { // Test selections via TreeFormula // tree is a TTree when called by stress9 @@ -184,6 +184,12 @@ TDirectory* GenerateDrawHist(TTree *tree,int level = 2, int quietLevel = 0) "", "hAlt", level>1 && gBranchStyle!=0); + // Test on the @ notation to access the collection object itself + DrawSkippable(tree,"event.@fTracks.size()","","hSize",level>2 && !(gBranchStyle==0 && !gHasLibrary)); + DrawSkippable(tree,"event.fTracks@.size()","","+hSize",level>2 && !(gBranchStyle==0 && !gHasLibrary)); + DrawSkippable(tree,"@fTracks.size()","","hSize2",level>2 && gBranchStyle!=0); + DrawSkippable(tree,"fTracks@.size()","","+hSize2",level>2 && gBranchStyle!=0); + if (quietLevel<2) gBenchmark->Show("DrawTest"); else gBenchmark->Stop("DrawTest"); gBenchmark->Start("DrawTest"); diff --git a/test/dt_MakeRef.C b/test/dt_MakeRef.C index 7fc8e3b9a708e7025d2904dd3e60deb5028b8879..79ea35022b0a17cc9c49fd7a12f14f7d64978437 100644 --- a/test/dt_MakeRef.C +++ b/test/dt_MakeRef.C @@ -117,6 +117,9 @@ void MakeHisto(TTree *tree, TDirectory* To) { TH1F *refAlt = RefClone(where,"hAlt"); + TH1F *refSize = RefClone(where,"hSize"); + TH1F *refSize2 = RefClone(where,"hSize2"); + // Loop with user code on all events and fill the ref histograms // The code below should produce identical results to the tree->Draw above @@ -193,6 +196,10 @@ void MakeHisto(TTree *tree, TDirectory* To) { if (bits.TestBitNumber(10)) refFiltTriggerBits->Fill(nbits); ntracks = event->GetNtrack(); + refSize->Fill(ntracks); + refSize->Fill(ntracks); + refSize2->Fill(ntracks); + refSize2->Fill(ntracks); if ( 5 < ntracks ) { t = (Track*)tracks->UncheckedAt(5); for(i0=0;i0<4;i0++) { diff --git a/test/dt_RunDrawTest.C b/test/dt_RunDrawTest.C index c17d0c9a5ad9983efa00e332d795c0f1a9bf4290..ebc3803449570031cd917a88109c6b0de7c916bc 100644 --- a/test/dt_RunDrawTest.C +++ b/test/dt_RunDrawTest.C @@ -172,7 +172,7 @@ bool dt_RunDrawTest(const char* from, Int_t mode = 0, Int_t verboseLevel = 0) { // cerr << "Branch style is " << gBranchStyle << endl; if (gQuietLevel<2) cout << "Generating histograms from TTree::Draw" << endl; - TDirectory* where = GenerateDrawHist(tree,2,gQuietLevel); + TDirectory* where = GenerateDrawHist(tree,gQuietLevel); if (gQuietLevel<2) cout << "Comparing histograms" << endl; if (Compare(where)>0) { diff --git a/tree/src/TTree.cxx b/tree/src/TTree.cxx index fb29f45812b636836654dd82abc1419260708187..2cde04804c107d546878a2319596b28745e2e319 100644 --- a/tree/src/TTree.cxx +++ b/tree/src/TTree.cxx @@ -1,4 +1,4 @@ -// @(#)root/tree:$Name: $:$Id: TTree.cxx,v 1.237 2005/03/07 18:08:25 brun Exp $ +// @(#)root/tree:$Name: $:$Id: TTree.cxx,v 1.238 2005/03/10 17:57:04 rdm Exp $ // Author: Rene Brun 12/01/96 /************************************************************************* @@ -2220,6 +2220,26 @@ Long64_t TTree::Draw(const char *varexp, const char *selection, Option_t *option // will not reset hsqrt, but will continue filling. // This works for 1-D, 2-D and 3-D histograms. // +// Accessing collection objects +// ============================ +// +// TTree::Draw default's handling of collections is to assume that any +// request on a collection pertain to it content. For example, if fTracks +// is a collection of Track objects, the following: +// tree->Draw("event.fTracks.fPx"); +// will plot the value of fPx for each Track objects inside the collection. +// Also +// tree->Draw("event.fTracks.size()"); +// would plot the result of the member function Track::size() for each +// Track object inside the collection. +// To access information about the collection itself, TTree::Draw support +// the '@' notation. If a variable which points to a collection is prefixed +// or postfixed with '@', the next part of the expression will pertain to +// the collection object. For example: +// tree->Draw("event.@fTracks.size()"); +// will plot the size of the collection refered to by fTracks (i.e the number +// of Track objects). +// // Special functions and variables // =============================== // diff --git a/treeplayer/inc/TFormLeafInfo.h b/treeplayer/inc/TFormLeafInfo.h index b5d0f6069e3cb702a88ad0369c32e6dcb978b326..89479334507ab4543dde6215f9c802da5a6e5a60 100644 --- a/treeplayer/inc/TFormLeafInfo.h +++ b/treeplayer/inc/TFormLeafInfo.h @@ -1,4 +1,4 @@ -// @(#)root/treeplayer:$Name: $:$Id: TFormLeafInfo.h,v 1.1 2004/06/17 17:37:10 brun Exp $ +// @(#)root/treeplayer:$Name: $:$Id: TFormLeafInfo.h,v 1.2 2005/02/25 19:13:24 brun Exp $ // Author: Philippe Canal 01/06/2004 /************************************************************************* @@ -127,6 +127,29 @@ public: virtual Bool_t Update(); }; +//______________________________________________________________________________ +// +// TFormLeafInfoCollectionObject +// This class is used when we are interested by the collection it self and +// it is split. + +class TFormLeafInfoCollectionObject : public TFormLeafInfo { +public: + TFormLeafInfoCollectionObject(TClass* classptr = 0); + + virtual TFormLeafInfo* DeepCopy() const { + return new TFormLeafInfoCollectionObject(*this); + } + + virtual Int_t GetCounterValue(TLeaf* leaf); + virtual Double_t ReadValue(char *where, Int_t instance = 0); + virtual Double_t GetValue(TLeaf *leaf, Int_t instance = 0); + virtual void *GetValuePointer(TLeaf *leaf, Int_t instance = 0); + virtual void *GetValuePointer(char *thisobj, Int_t instance = 0); + virtual void *GetLocalValuePointer(TLeaf *leaf, Int_t instance = 0); + virtual void *GetLocalValuePointer(char *thisobj, Int_t instance = 0); +}; + //______________________________________________________________________________ // // TFormLeafInfoClones is a small helper class to implement reading a data diff --git a/treeplayer/inc/TTreeFormula.h b/treeplayer/inc/TTreeFormula.h index e8ef5eec11fcfb331908acafee893e39ace2e7d6..cb7e48e26f8db462974afd96f1aef1abf183224b 100644 --- a/treeplayer/inc/TTreeFormula.h +++ b/treeplayer/inc/TTreeFormula.h @@ -1,4 +1,4 @@ -// @(#)root/treeplayer:$Name: $:$Id: TTreeFormula.h,v 1.41 2005/02/18 09:15:08 rdm Exp $ +// @(#)root/treeplayer:$Name: $:$Id: TTreeFormula.h,v 1.42 2005/03/08 05:33:30 brun Exp $ // Author: Rene Brun 19/01/96 /************************************************************************* @@ -111,12 +111,12 @@ protected: Bool_t BranchHasMethod(TLeaf* leaf, TBranch* branch, const char* method,const char* params, Long64_t readentry) const; Int_t DefineAlternate(const char* expression); void DefineDimensions(Int_t code, Int_t size, TFormLeafInfoMultiVarDim * info, Int_t& virt_dim); - Int_t FindLeafForExpression(const char* expression, TLeaf *&leaf, TString &leftover, Bool_t &final, UInt_t ¶n_level, TObjArray &castqueue, std::vector<std::string>&, const char *fullExpression); + Int_t FindLeafForExpression(const char* expression, TLeaf *&leaf, TString &leftover, Bool_t &final, UInt_t ¶n_level, TObjArray &castqueue, std::vector<std::string>& aliasUsed, Bool_t &useLeafCollectionObject, const char *fullExpression); TLeaf* GetLeafWithDatamember(const char* topchoice, const char* nextchice, Long64_t readentry) const; - Int_t ParseWithLeaf(TLeaf *leaf, const char *expression, Bool_t final, UInt_t paran_level, TObjArray &castqueue, const char *fullExpression); - Int_t RegisterDimensions(Int_t code, Int_t size, TFormLeafInfoMultiVarDim * multidim = 0); + Int_t ParseWithLeaf(TLeaf *leaf, const char *expression, Bool_t final, UInt_t paran_level, TObjArray &castqueue, Bool_t useLeafCollectionObject, const char *fullExpression); + Int_t RegisterDimensions(Int_t code, Int_t size, TFormLeafInfoMultiVarDim * multidim = 0); Int_t RegisterDimensions(Int_t code, TBranchElement *branch); - Int_t RegisterDimensions(Int_t code, TFormLeafInfo *info); + Int_t RegisterDimensions(Int_t code, TFormLeafInfo *info, Bool_t useCollectionObject); Int_t RegisterDimensions(Int_t code, TLeaf *leaf); Int_t RegisterDimensions(const char *size, Int_t code); diff --git a/treeplayer/src/TFormLeafInfo.cxx b/treeplayer/src/TFormLeafInfo.cxx index f5218d45f6ed0d2fc1d2e6b19779588dcf4a8478..c0152d51e7f318ccc5916e400abc730f6cf5e2df 100644 --- a/treeplayer/src/TFormLeafInfo.cxx +++ b/treeplayer/src/TFormLeafInfo.cxx @@ -1,4 +1,4 @@ -// @(#)root/treeplayer:$Name: $:$Id: TFormLeafInfo.cxx,v 1.14 2005/02/25 19:13:24 brun Exp $ +// @(#)root/treeplayer:$Name: $:$Id: TFormLeafInfo.cxx,v 1.15 2005/02/25 21:49:04 brun Exp $ // Author: Philippe Canal 01/06/2004 /************************************************************************* @@ -875,17 +875,17 @@ Bool_t TFormLeafInfoNumerical::Update() return kFALSE; } -//______________________________________________________________________________ -// -// TFormLeafInfoClones is a small helper class to implement reading a data member -// on a TClonesArray object stored in a TTree. - namespace { static TStreamerElement gFakeClonesElem("begin","fake",0, TStreamerInfo::kAny, "TClonesArray"); } +//______________________________________________________________________________ +// +// TFormLeafInfoClones is a small helper class to implement reading a data member +// on a TClonesArray object stored in a TTree. + //______________________________________________________________________________ TFormLeafInfoClones::TFormLeafInfoClones(TClass* classptr, Long_t offset) : TFormLeafInfo(classptr,offset,&gFakeClonesElem),fTop(kFALSE) @@ -1032,6 +1032,86 @@ void * TFormLeafInfoClones::GetValuePointer(char *where, Int_t instance) { return clones; } +//______________________________________________________________________________ +// +// TFormLeafInfoCollectionObject is a small helper class to implement reading a data member +// on a TClonesArray object stored in a TTree. + +//______________________________________________________________________________ +TFormLeafInfoCollectionObject::TFormLeafInfoCollectionObject(TClass* classptr) : + TFormLeafInfo(classptr,0,&gFakeClonesElem) +{ +} + +//______________________________________________________________________________ +Int_t TFormLeafInfoCollectionObject::GetCounterValue(TLeaf* leaf) +{ + // Return the current size of the the TClonesArray + + return 1; +} + +//______________________________________________________________________________ +Double_t TFormLeafInfoCollectionObject::ReadValue(char *where, Int_t instance) +{ + // Return the value of the underlying data member inside the + // clones array. + + Assert(0); + return 0; +} + +//______________________________________________________________________________ +void* TFormLeafInfoCollectionObject::GetLocalValuePointer(TLeaf *leaf, Int_t /*instance*/) +{ + // Return the pointer to the clonesArray + + void* collection; + if (leaf->InheritsFrom("TLeafObject") ) { + collection = ((TLeafObject*)leaf)->GetObject(); + } else { + collection = ((TBranchElement*)leaf->GetBranch())->GetObject(); + } + return collection; +} + +//______________________________________________________________________________ +void* TFormLeafInfoCollectionObject::GetLocalValuePointer(char *where, Int_t instance) { + return TFormLeafInfo::GetLocalValuePointer(where,instance); +} + +//______________________________________________________________________________ +Double_t TFormLeafInfoCollectionObject::GetValue(TLeaf *leaf, Int_t instance) { + // Return the value of the underlying data member inside the + // clones array. + + char * obj = (char*)GetLocalValuePointer(leaf); + + if (fNext==0) return 0; + return fNext->ReadValue(obj,instance); +} + +//______________________________________________________________________________ +void * TFormLeafInfoCollectionObject::GetValuePointer(TLeaf *leaf, Int_t instance) { + // Return the pointer to the clonesArray + + void *collection = GetLocalValuePointer(leaf); + if (fNext) { + return fNext->GetValuePointer((char*)collection,instance); + } + return collection; +} + +//______________________________________________________________________________ +void * TFormLeafInfoCollectionObject::GetValuePointer(char *where, Int_t instance) { + // Return the pointer to the clonesArray + + if (fNext) { + return fNext->GetValuePointer(where,instance); + } + return where; +} + //______________________________________________________________________________ // // TFormLeafInfoCollection is a small helper class to implement reading a data diff --git a/treeplayer/src/TTreeFormula.cxx b/treeplayer/src/TTreeFormula.cxx index 090b9af76f6d4519ac528e12aca73702640947a4..dafded656e3d0a473411ef4da32b2ba43484239a 100644 --- a/treeplayer/src/TTreeFormula.cxx +++ b/treeplayer/src/TTreeFormula.cxx @@ -1,4 +1,4 @@ -// @(#)root/treeplayer:$Name: $:$Id: TTreeFormula.cxx,v 1.168 2005/03/07 17:00:17 brun Exp $ +// @(#)root/treeplayer:$Name: $:$Id: TTreeFormula.cxx,v 1.169 2005/03/08 05:33:30 brun Exp $ // Author: Rene Brun 19/01/96 /************************************************************************* @@ -395,7 +395,8 @@ Int_t TTreeFormula::RegisterDimensions(Int_t code, Int_t size, TFormLeafInfoMult } //______________________________________________________________________________ -Int_t TTreeFormula::RegisterDimensions(Int_t code, TFormLeafInfo *leafinfo) { +Int_t TTreeFormula::RegisterDimensions(Int_t code, TFormLeafInfo *leafinfo, + Bool_t useCollectionObject) { // This method is used internally to decode the dimensions of the variables Int_t ndim, size, current, vardim; @@ -428,7 +429,7 @@ Int_t TTreeFormula::RegisterDimensions(Int_t code, TFormLeafInfo *leafinfo) { TStreamerElement* counter = cl->GetStreamerInfo()->GetStreamerElement(array->GetCountName(),offset); leafinfo->fCounter = new TFormLeafInfo(cl,offset,counter); - } else if (elem->GetClassPointer() == TClonesArray::Class() ) { + } else if (!useCollectionObject && elem->GetClassPointer() == TClonesArray::Class() ) { ndim = 1; size = -1; @@ -438,7 +439,7 @@ Int_t TTreeFormula::RegisterDimensions(Int_t code, TFormLeafInfo *leafinfo) { TStreamerElement *counter = ClonesClass->GetStreamerInfo()->GetStreamerElement("fLast",c_offset); leafinfo->fCounter = new TFormLeafInfo(ClonesClass,c_offset,counter); - } else if (elem->GetClassPointer() && elem->GetClassPointer()->GetCollectionProxy() ) { + } else if (!useCollectionObject && elem->GetClassPointer() && elem->GetClassPointer()->GetCollectionProxy() ) { if ( typeid(*leafinfo) == typeid(TFormLeafInfoCollection) ) { ndim = 1; @@ -647,8 +648,9 @@ Int_t TTreeFormula::DefineAlternate(const char *expression) //______________________________________________________________________________ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, Bool_t final, UInt_t paran_level, - TObjArray &castqueue, - const char* fullExpression) + TObjArray &castqueue, + Bool_t useLeafCollectionObject, + const char* fullExpression) { // Decompose 'expression' as pointing to something inside the leaf // Returns: @@ -874,69 +876,87 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, unwindCollection = kTRUE; } - } else if (BranchEl->GetType()==3) { - - TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(cl, 0, kTRUE); - // The dimension needs to be handled! - numberOfVarDim += RegisterDimensions(code,clonesinfo); + } else if ( BranchEl->GetType()==3) { + TFormLeafInfo* clonesinfo; + if (useLeafCollectionObject) { + clonesinfo = new TFormLeafInfoCollectionObject(cl); + } else { + clonesinfo = new TFormLeafInfoClones(cl, 0, kTRUE); + // The dimension needs to be handled! + numberOfVarDim += RegisterDimensions(code,clonesinfo,useLeafCollectionObject); + } maininfo = clonesinfo; previnfo = maininfo; - } else if (BranchEl->GetType()==4) { + } else if (!useLeafCollectionObject && BranchEl->GetType()==4) { - TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, kTRUE); - // The dimension needs to be handled! - numberOfVarDim += RegisterDimensions(code,collectioninfo); + TFormLeafInfo* collectioninfo; + if (useLeafCollectionObject) { + collectioninfo = new TFormLeafInfoCollectionObject(cl); + } else { + collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, kTRUE); + // The dimension needs to be handled! + numberOfVarDim += RegisterDimensions(code,collectioninfo,useLeafCollectionObject); + } maininfo = collectioninfo; previnfo = maininfo; } else if (BranchEl->GetStreamerType()==-1 && cl && cl->GetCollectionProxy()) { - TFormLeafInfo *collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, kTRUE); - // The dimension needs to be handled! - numberOfVarDim += RegisterDimensions(code,collectioninfo); + if (useLeafCollectionObject) { - maininfo = collectioninfo; - previnfo = collectioninfo; - - if (cl->GetCollectionProxy()->GetValueClass()!=0 && - cl->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()!=0) { + TFormLeafInfo *collectioninfo = new TFormLeafInfoCollectionObject(cl); + maininfo = collectioninfo; + previnfo = collectioninfo; - TFormLeafInfo *multi = new TFormLeafInfoMultiVarDimCollection(cl,0, - cl->GetCollectionProxy()->GetValueClass(),collectioninfo); + } else { + TFormLeafInfo *collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, kTRUE); + // The dimension needs to be handled! + numberOfVarDim += RegisterDimensions(code,collectioninfo,kFALSE); - fHasMultipleVarDim[code] = kTRUE; - numberOfVarDim += RegisterDimensions(code,multi); - previnfo->fNext = multi; - cl = cl->GetCollectionProxy()->GetValueClass(); - multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false); - previnfo = multi->fNext; + maininfo = collectioninfo; + previnfo = collectioninfo; - } - if (cl->GetCollectionProxy()->GetValueClass()==0 && - cl->GetCollectionProxy()->GetType()>0) { + if (cl->GetCollectionProxy()->GetValueClass()!=0 && + cl->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()!=0) { - previnfo->fNext = - new TFormLeafInfoNumerical(cl->GetCollectionProxy()->GetType()); - previnfo = previnfo->fNext; - } else { - // nothing to do + TFormLeafInfo *multi = new TFormLeafInfoMultiVarDimCollection(cl,0, + cl->GetCollectionProxy()->GetValueClass(),collectioninfo); + + fHasMultipleVarDim[code] = kTRUE; + numberOfVarDim += RegisterDimensions(code,multi, kFALSE); + previnfo->fNext = multi; + cl = cl->GetCollectionProxy()->GetValueClass(); + multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false); + previnfo = multi->fNext; + + } + if (cl->GetCollectionProxy()->GetValueClass()==0 && + cl->GetCollectionProxy()->GetType()>0) { + + previnfo->fNext = + new TFormLeafInfoNumerical(cl->GetCollectionProxy()->GetType()); + previnfo = previnfo->fNext; + } else { + // nothing to do + } } } else if (strlen(right)==0 && cl && element && final) { TClass *elemCl = element->GetClassPointer(); - if (elemCl && elemCl->GetCollectionProxy() - && elemCl->GetCollectionProxy()->GetValueClass() - && elemCl->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()) { + if (!useLeafCollectionObject + && elemCl && elemCl->GetCollectionProxy() + && elemCl->GetCollectionProxy()->GetValueClass() + && elemCl->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()) { TFormLeafInfo *collectioninfo = new TFormLeafInfoCollection(cl, 0, elemCl); // The dimension needs to be handled! - numberOfVarDim += RegisterDimensions(code,collectioninfo); + numberOfVarDim += RegisterDimensions(code,collectioninfo,kFALSE); maininfo = collectioninfo; previnfo = collectioninfo; @@ -947,7 +967,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, collectioninfo); fHasMultipleVarDim[code] = kTRUE; - numberOfVarDim += RegisterDimensions(code,multi); + numberOfVarDim += RegisterDimensions(code,multi,kFALSE); previnfo->fNext = multi; cl = elemCl->GetCollectionProxy()->GetValueClass(); multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false); @@ -961,7 +981,8 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, previnfo = previnfo->fNext; } - } else if (elemCl && elemCl->GetCollectionProxy() + } else if (!useLeafCollectionObject + && elemCl && elemCl->GetCollectionProxy() && elemCl->GetCollectionProxy()->GetValueClass()==0 && elemCl->GetCollectionProxy()->GetType()>0) { @@ -974,7 +995,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, new TFormLeafInfoCollection(cl, 0, elemCl); // The dimension needs to be handled! - numberOfVarDim += RegisterDimensions(code,collectioninfo); + numberOfVarDim += RegisterDimensions(code,collectioninfo, kFALSE); collectioninfo->fNext = new TFormLeafInfoNumerical(elemCl->GetCollectionProxy()->GetType()); @@ -1001,11 +1022,11 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, // directly a collection. Assert(numberOfVarDim==1 && maininfo); - if (cl && cl->GetCollectionProxy()) { + if (!useLeafCollectionObject && cl && cl->GetCollectionProxy()) { TFormLeafInfo *multi = new TFormLeafInfoMultiVarDimCollection(cl, 0, cl, maininfo); fHasMultipleVarDim[code] = kTRUE; - numberOfVarDim += RegisterDimensions(code,multi); + numberOfVarDim += RegisterDimensions(code,multi,kFALSE); previnfo->fNext = multi; multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false); @@ -1057,6 +1078,8 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, } Int_t i; + Bool_t prevUseCollectionObject = useLeafCollectionObject; + Bool_t useCollectionObject = useLeafCollectionObject; for (i=0, current = &(work[0]); i<=nchname;i++ ) { // We will treated the terminator as a token. if (right[i] == '(') { @@ -1078,8 +1101,8 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, Error("DefinedVariable","Class probably unavailable:%s",cl->GetName()); return -2; } - if (cl == TClonesArray::Class()) { - // We are NEVER interested in the ClonesArray object but only + if (!useCollectionObject && cl == TClonesArray::Class()) { + // We are not interested in the ClonesArray object but only // in its contents. // We need to retrieve the class of its content. @@ -1100,7 +1123,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0, top); // The dimension needs to be handled! - numberOfVarDim += RegisterDimensions(code,clonesinfo); + numberOfVarDim += RegisterDimensions(code,clonesinfo, kFALSE); previnfo = clonesinfo; maininfo = clonesinfo; @@ -1110,7 +1133,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, TClass * inside_cl = clones->GetClass(); if (1 || inside_cl) cl = inside_cl; - } else if (cl && cl->GetCollectionProxy() ) { + } else if (!useCollectionObject && cl && cl->GetCollectionProxy() ) { // We are NEVER (for now!) interested in the ClonesArray object but only // in its contents. @@ -1132,7 +1155,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(mother_cl, 0,cl,top); // The dimension needs to be handled! - numberOfVarDim += RegisterDimensions(code,collectioninfo); + numberOfVarDim += RegisterDimensions(code,collectioninfo, kFALSE); previnfo = collectioninfo; maininfo = collectioninfo; @@ -1147,34 +1170,46 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, } } - TMethodCall *method; - if (cl->GetClassInfo()==0) { + TMethodCall *method = 0; + if (cl==0) { Error("DefinedVariable", - "Can not call method %s on class without dictionary (%s)!", - right,cl->GetName()); + "Could not discover the TClass corresponding to (%s)!", + right); return -2; + } else if (cl==TClonesArray::Class() && strcmp(work,"size")==0) { + method = new TMethodCall(cl, "GetEntriesFast", ""); + } else if (cl->GetCollectionProxy() && strcmp(work,"size")==0) { + leafinfo = new TFormLeafInfoCollectionSize(cl); + } else { + if (cl->GetClassInfo()==0) { + Error("DefinedVariable", + "Can not call method %s on class without dictionary (%s)!", + right,cl->GetName()); + return -2; + } + method = new TMethodCall(cl, work, params); } - method = new TMethodCall(cl, work, params); - if (!method->GetMethod()) { - Error("DefinedVariable","Unknown method:%s",right); - return -1; - } - switch(method->ReturnType()) { - case TMethodCall::kLong: + if (method) { + if (!method->GetMethod()) { + Error("DefinedVariable","Unknown method:%s in %s",right,cl->GetName()); + return -1; + } + switch(method->ReturnType()) { + case TMethodCall::kLong: leafinfo = new TFormLeafInfoMethod(cl,method); cl = 0; break; - case TMethodCall::kDouble: + case TMethodCall::kDouble: leafinfo = new TFormLeafInfoMethod(cl,method); cl = 0; break; - case TMethodCall::kString: + case TMethodCall::kString: leafinfo = new TFormLeafInfoMethod(cl,method); // 1 will be replaced by -1 when we know how to use strlen numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0 cl = 0; break; - case TMethodCall::kOther: + case TMethodCall::kOther: { TString return_type = gInterpreter->TypeName(method->GetMethod()->GetReturnTypeName()); @@ -1185,10 +1220,11 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, cl = 0; } }; break; - default: - Error("DefineVariable","Method %s from %s has an impossible return type %d", - work,cl->GetName(),method->ReturnType()); - return -2; + default: + Error("DefineVariable","Method %s from %s has an impossible return type %d", + work,cl->GetName(),method->ReturnType()); + return -2; + } } if (maininfo==0) { maininfo = leafinfo; @@ -1202,6 +1238,8 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, leafinfo = 0; current = &(work[0]); *current = 0; + prevUseCollectionObject = kFALSE; + useCollectionObject = kFALSE; continue; } else if (right[i] == ')') { // We should have the end of a cast operator. Let's introduce a TFormLeafCast @@ -1236,9 +1274,22 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, // skip it all if there is nothing to look at if (strlen(work)==0) continue; + prevUseCollectionObject = useCollectionObject; + if (work[0]=='@') { + useCollectionObject = kTRUE; + Int_t l = 0; + for(l=0;work[l+1]!=0;++l) work[l] = work[l+1]; + work[l] = '\0'; + } else if (work[strlen(work)-1]=='@') { + useCollectionObject = kTRUE; + work[strlen(work)-1] = '\0'; + } else { + useCollectionObject = kFALSE; + } + Bool_t mustderef = kFALSE; - if (cl == TClonesArray::Class()) { - // We are NEVER interested in the ClonesArray object but only + if (!prevUseCollectionObject && cl == TClonesArray::Class()) { + // We are not interested in the ClonesArray object but only // in its contents. // We need to retrieve the class of its content. @@ -1261,7 +1312,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, TFormLeafInfo* clonesinfo = new TFormLeafInfoClones(mother_cl, 0); // The dimension needs to be handled! - numberOfVarDim += RegisterDimensions(code,clonesinfo); + numberOfVarDim += RegisterDimensions(code,clonesinfo, kFALSE); mustderef = kTRUE; previnfo = clonesinfo; @@ -1292,7 +1343,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, // so let get the number of objects //strcpy(work,"fLast"); } - } else if (cl && cl->GetCollectionProxy() ) { + } else if (!prevUseCollectionObject && cl && cl->GetCollectionProxy() ) { // We are NEVER interested in the Collection object but only // in its contents. @@ -1317,7 +1368,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, TFormLeafInfo* collectioninfo = new TFormLeafInfoCollection(mother_cl, 0, cl); // The dimension needs to be handled! - numberOfVarDim += RegisterDimensions(code,collectioninfo); + numberOfVarDim += RegisterDimensions(code,collectioninfo, kFALSE); mustderef = kTRUE; previnfo = collectioninfo; @@ -1343,7 +1394,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, element = cl->GetStreamerInfo()->GetStreamerElement(work,offset); } - if (!element) { + if (!element && !prevUseCollectionObject) { // We allow for looking for a data member inside a class inside // a TClonesArray without mentioning the TClonesArrays variable name TIter next( cl->GetStreamerInfo()->GetElements() ); @@ -1366,12 +1417,12 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, } TClass *sub_cl = clones->GetClass(); - element = sub_cl->GetStreamerInfo()->GetStreamerElement(work,offset); + if (sub_cl) element = sub_cl->GetStreamerInfo()->GetStreamerElement(work,offset); delete clonesinfo; if (element) { leafinfo = new TFormLeafInfoClones(cl,clones_offset,curelem); - numberOfVarDim += RegisterDimensions(code,leafinfo); + numberOfVarDim += RegisterDimensions(code,leafinfo, kFALSE); if (maininfo==0) maininfo = leafinfo; if (previnfo==0) previnfo = leafinfo; else { @@ -1402,10 +1453,10 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, curelem,maininfo); fHasMultipleVarDim[code] = kTRUE; leafinfo->fNext = new TFormLeafInfoCollection(cl,coll_offset,curelem); - numberOfVarDim += RegisterDimensions(code,leafinfo); + numberOfVarDim += RegisterDimensions(code,leafinfo, kFALSE); } else { leafinfo = new TFormLeafInfoCollection(cl,coll_offset,curelem); - numberOfVarDim += RegisterDimensions(code,leafinfo); + numberOfVarDim += RegisterDimensions(code,leafinfo, kFALSE); } if (maininfo==0) maininfo = leafinfo; if (previnfo==0) previnfo = leafinfo; @@ -1497,12 +1548,12 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, mustderef = kTRUE; } else { - if (element->GetClassPointer() == TClonesArray::Class()) { + if (!useCollectionObject && element->GetClassPointer() == TClonesArray::Class()) { leafinfo = new TFormLeafInfoClones(cl,offset,element); mustderef = kTRUE; - } else if (element->GetClassPointer() + } else if (!useCollectionObject && element->GetClassPointer() && element->GetClassPointer()->GetCollectionProxy()) { mustderef = kTRUE; @@ -1539,7 +1590,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, if (valueCl!=0 && valueCl->GetCollectionProxy()!=0) { - numberOfVarDim += RegisterDimensions(code,leafinfo); + numberOfVarDim += RegisterDimensions(code,leafinfo, kFALSE); if (previnfo==0) previnfo = leafinfo; else { previnfo->fNext = leafinfo; @@ -1578,7 +1629,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, return -1; } - numberOfVarDim += RegisterDimensions(code,leafinfo); + numberOfVarDim += RegisterDimensions(code,leafinfo, useCollectionObject); // Note or useCollectionObject||prevUseColectionObject if (maininfo==0) { maininfo = leafinfo; } @@ -1598,7 +1649,7 @@ Int_t TTreeFormula::ParseWithLeaf(TLeaf *leaf, const char *subExpression, *current = 0; Assert(right[i] != '['); // We are supposed to have removed all dimensions already! - + } else *current++ = right[i]; } @@ -1656,7 +1707,8 @@ Int_t TTreeFormula::FindLeafForExpression(const char* expression, TLeaf *&leaf, TString &leftover, Bool_t &final, UInt_t ¶n_level, TObjArray &castqueue, - std::vector<std::string>& aliasUsed, + std::vector<std::string>& aliasUsed, + Bool_t &useLeafCollectionObject, const char *fullExpression) { // Look for the leaf corresponding to the start of expression. @@ -1690,6 +1742,7 @@ Int_t TTreeFormula::FindLeafForExpression(const char* expression, Int_t nchname = strlen(cname); Int_t i; + Bool_t foundAtSign = kFALSE; for (i=0, current = &(work[0]); i<=nchname && !final;i++ ) { // We will treated the terminator as a token. @@ -1789,6 +1842,21 @@ Int_t TTreeFormula::FindLeafForExpression(const char* expression, // so far does point to a leaf. *current = '\0'; + if (work[0]=='@') { + foundAtSign = kTRUE; + Int_t l = 0; + for(l=0;work[l+1]!=0;++l) work[l] = work[l+1]; + work[l] = '\0'; + --current; + } else if (work[strlen(work)-2]=='@') { + foundAtSign = kTRUE; + work[strlen(work)-2] = cname[i]; + work[strlen(work)-1] = '\0'; + --current; + } else { + foundAtSign = kFALSE; + } + if (left[0]==0) strcpy(left,work); if (!leaf && !branch) { // So far, we have not found a matching leaf or branch. @@ -1803,7 +1871,7 @@ Int_t TTreeFormula::FindLeafForExpression(const char* expression, if (!branch) branch = fTree->FindBranch(first); if (!leaf) leaf = fTree->FindLeaf(first); - if (branch && cname[i] != 0) { + if (branch && (foundAtSign || cname[i] != 0) ) { // Since we found a branch and there is more information in the name, // we do NOT look at the 'IsOnTerminalBranch' status of the leaf // we found ... yet! @@ -1816,11 +1884,21 @@ Int_t TTreeFormula::FindLeafForExpression(const char* expression, if ( type == 3 || type ==4) { // We have a Collection branch. leaf = (TLeaf*)branch->GetListOfLeaves()->At(0); + if (foundAtSign) { + useLeafCollectionObject = foundAtSign; + foundAtSign = kFALSE; + current = &(work[0]); + *current = 0; + ++i; + break; + } } } } // we reset work + useLeafCollectionObject = foundAtSign; + foundAtSign = kFALSE; current = &(work[0]); *current = 0; } else if (leaf || branch) { @@ -1851,6 +1929,7 @@ Int_t TTreeFormula::FindLeafForExpression(const char* expression, final = kTRUE; strcpy(right,first); //We need to put the delimiter back! + if (foundAtSign) strcat(right,"@"); if (cname[i]=='.') strcat(right,"."); // We reset work @@ -1927,14 +2006,24 @@ Int_t TTreeFormula::FindLeafForExpression(const char* expression, if (second[0]) strcat(second,"."); strcat(second,work); leaf = tmp_leaf; + useLeafCollectionObject = foundAtSign; + foundAtSign = kFALSE; // we reset work current = &(work[0]); *current = 0; } else { //We need to put the delimiter back! - if (strlen(work)) work[strlen(work)] = cname[i]; - else --current; + if (strlen(work)) { + if (foundAtSign) { + Int_t where = strlen(work); + work[where] = '@'; + work[where+1] = cname[i]; + ++current; + } else { + work[strlen(work)] = cname[i]; + } + } else --current; } } } @@ -1987,7 +2076,8 @@ Int_t TTreeFormula::FindLeafForExpression(const char* expression, aliasUsed.push_back(left); TString newExpression = aliasValue; newExpression += (cname+strlen(left)); - Int_t res = FindLeafForExpression(newExpression, leaf, leftover, final, paran_level, castqueue, aliasUsed, fullExpression); + Int_t res = FindLeafForExpression(newExpression, leaf, leftover, final, paran_level, + castqueue, aliasUsed, useLeafCollectionObject, fullExpression); if (res<0) { Error("DefinedVariable", "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue); @@ -2125,11 +2215,12 @@ Int_t TTreeFormula::DefinedVariable(TString &name, Int_t &action) } cname[k]='\0'; + Bool_t useLeafCollectionObject = kFALSE; TString leftover; TLeaf *leaf = 0; { std::vector<std::string> aliasSofar = fAliasesUsed; - res = FindLeafForExpression(cname, leaf, leftover, final, paran_level, castqueue, aliasSofar, name); + res = FindLeafForExpression(cname, leaf, leftover, final, paran_level, castqueue, aliasSofar, useLeafCollectionObject, name); } if (res<0) return res; @@ -2230,7 +2321,7 @@ Int_t TTreeFormula::DefinedVariable(TString &name, Int_t &action) // Now that we have clean-up the expression, let's compare it to the content // of the leaf! - Int_t res = ParseWithLeaf(leaf,leftover,final,paran_level,castqueue,name); + Int_t res = ParseWithLeaf(leaf,leftover,final,paran_level,castqueue,useLeafCollectionObject,name); if (res<0) return res; if (res>0) action = res; return code; diff --git a/treeplayer/src/TTreePlayer.cxx b/treeplayer/src/TTreePlayer.cxx index bd59441e1868c8d8237166509e0950f544d97a51..de407167806698dde4984791a7d890517270469b 100644 --- a/treeplayer/src/TTreePlayer.cxx +++ b/treeplayer/src/TTreePlayer.cxx @@ -1,4 +1,4 @@ -// @(#)root/treeplayer:$Name: $:$Id: TTreePlayer.cxx,v 1.182 2005/03/04 17:46:50 brun Exp $ +// @(#)root/treeplayer:$Name: $:$Id: TTreePlayer.cxx,v 1.183 2005/03/07 18:48:27 brun Exp $ // Author: Rene Brun 12/01/96 /************************************************************************* @@ -663,6 +663,26 @@ Long64_t TTreePlayer::DrawSelect(const char *varexp0, const char *selection, Opt // will not reset hsqrt, but will continue filling. // This works for 1-D, 2-D and 3-D histograms. // +// Accessing collection objects +// ============================ +// +// TTree::Draw default's handling of collections is to assume that any +// request on a collection pertain to it content. For example, if fTracks +// is a collection of Track objects, the following: +// tree->Draw("event.fTracks.fPx"); +// will plot the value of fPx for each Track objects inside the collection. +// Also +// tree->Draw("event.fTracks.size()"); +// would plot the result of the member function Track::size() for each +// Track object inside the collection. +// To access information about the collection itself, TTree::Draw support +// the '@' notation. If a variable which points to a collection is prefixed +// or postfixed with '@', the next part of the expression will pertain to +// the collection object. For example: +// tree->Draw("event.@fTracks.size()"); +// will plot the size of the collection refered to by fTracks (i.e the number +// of Track objects). +// // Special functions and variables // =============================== //