// @(#)root/tree:$Name: $:$Id: TBranchElement.cxx,v 1.178 2005/08/29 10:57:28 brun Exp $
// Authors Rene Brun , Philippe Canal, Markus Frank 14/01/2001
/*************************************************************************
* Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TBranchElement //
// //
// A Branch for the case of an object //
// //
//////////////////////////////////////////////////////////////////////////
#include "TROOT.h"
#include "TFile.h"
#include "TBranchElement.h"
#include "TBranchObject.h"
#include "TBranchRef.h"
#include "TClonesArray.h"
#include "TTree.h"
#include "TBasket.h"
#include "TLeafElement.h"
#include "TVirtualPad.h"
#include "TClass.h"
#include "TClassEdit.h"
#include "TDataType.h"
#include "TDataMember.h"
#include "TStreamerInfo.h"
#include "TStreamerElement.h"
#include "TBrowser.h"
#include "TFolder.h"
#include "TRealData.h"
#include "Api.h"
#include "TError.h"
#include "TVirtualCollectionProxy.h"
const Int_t kMaxLen = 1024;
R__EXTERN TTree *gTree;
ClassImp(TBranchElement)
//______________________________________________________________________________
TBranchElement::TBranchElement(): TBranch(), fCurrentClass(), fParentClass(), fBranchClass()
{
//*-*-*-*-*-*Default constructor for BranchElement*-*-*-*-*-*-*-*-*-*
//*-* ====================================
fNleaves = 1;
fInfo = 0;
fBranchCount = 0;
fBranchCount2 = 0;
fObject = 0;
fMaximum = 0;
fBranchPointer = 0;
fNdata = 1;
fSTLtype = TClassEdit::kNotSTL;
fCollProxy = 0;
fCheckSum = 0;
fBranchOffset = 0;
fBranchTypes = 0;
fParentOffset = 0;
fInit = fInitOffsets = kFALSE;
}
//______________________________________________________________________________
TBranchElement::TBranchElement(const char *bname, TStreamerInfo *sinfo, Int_t id, char *pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
:TBranch(), fCurrentClass(), fParentClass(), fBranchClass(sinfo->GetClass())
{
// Create a BranchElement
//
// If splitlevel > 0 this branch in turn is split into sub branches
fCollProxy = 0;
if (gDebug > 0) {
printf("BranchElement, bname=%s, sinfo=%s, id=%d, splitlevel=%d\n",bname,sinfo->GetName(),id,splitlevel);
}
char name[kMaxLen];
strcpy(name,bname);
SetName(name);
SetTitle(name);
fSplitLevel = splitlevel;
if (id < 0) splitlevel = 0;
TClass *cl = sinfo->GetClass();
fInfo = sinfo;
fCheckSum = sinfo->GetCheckSum();
fID = id;
fInit = kTRUE;
fStreamerType = -1;
fType = 0;
fBranchCount = 0;
fBranchCount2 = 0;
fObject = 0;
fBranchPointer= 0;
fNdata = 1;
fSTLtype = TClassEdit::kNotSTL;
fClassVersion = cl->GetClassVersion();
fTree = gTree;
fMaximum = 0;
fBranchOffset = 0;
fParentOffset = 0;
fBranchTypes = 0;
fInitOffsets = kFALSE;
ULong_t *elems = sinfo->GetElems();
TStreamerElement *element = 0;
TBranchElement *brcount = 0;
if (id >= 0) {
element = (TStreamerElement *)elems[id];
fStreamerType = element->GetType();
if (fStreamerType == TStreamerInfo::kObject
|| fStreamerType == TStreamerInfo::kBase
|| fStreamerType == TStreamerInfo::kTNamed
|| fStreamerType == TStreamerInfo::kTObject
|| fStreamerType == TStreamerInfo::kObjectp
|| fStreamerType == TStreamerInfo::kObjectP) {
if (cl->InheritsFrom(TObject::Class())) SetBit(kBranchObject);
}
if (element->IsA() == TStreamerBasicPointer::Class()) {
TStreamerBasicPointer *bp = (TStreamerBasicPointer *)element;
char countname[kMaxLen];
strcpy(countname,bname);
char *dot = strrchr(countname,'.');
if (dot) *(dot+1) = 0;
else countname[0] = 0;
strcat(countname,bp->GetCountName());
brcount = (TBranchElement *)fTree->GetBranch(countname);
sprintf(countname,"%s[%s]",name,bp->GetCountName());
SetTitle(countname);
}
} else {
if (cl->InheritsFrom(TObject::Class())) SetBit(kBranchObject);
}
// Set the bit kAutoDelete to specify that when reading
// the object should be deleted before calling Streamer.
// It is foreseen to not set this bit in a future version.
//SetAutoDelete(kTRUE);
SetAutoDelete(kFALSE);
fDirectory = fTree->GetDirectory();
fFileName = "";
fClassName = sinfo->GetName();
if (gDebug > 1) printf("Building Branch=%s, class=%s, info=%s, version=%d, id=%d, fStreamerType=%d, btype=%d\n",bname,cl->GetName(),sinfo->GetName(),fClassVersion,id,fStreamerType,btype);
fCompress = -1;
if (gTree->GetDirectory()) {
TFile *bfile = gTree->GetDirectory()->GetFile();
if (bfile) fCompress = bfile->GetCompressionLevel();
}
//change defaults set in TBranch constructor
fEntryOffsetLen = 0;
if (btype || fStreamerType <= 0
|| fStreamerType == 7
|| fStreamerType > 15) fEntryOffsetLen = 1000;
if (basketsize < 100+fEntryOffsetLen) basketsize = 100+fEntryOffsetLen;
fBasketSize = basketsize;
fBasketBytes = new Int_t[fMaxBaskets];
fBasketEntry = new Long64_t[fMaxBaskets];
fBasketSeek = new Long64_t[fMaxBaskets];
for (Int_t i=0;i<fMaxBaskets;i++) {
fBasketBytes[i] = 0;
fBasketEntry[i] = 0;
fBasketSeek[i] = 0;
}
// Create a basket for the terminal branch
TBasket *basket = new TBasket(name,fTree->GetName(),this);
fBaskets.Add(basket);
// save pointer (if non null). Will be used in Unroll in case we find
// a TClonesArray in a derived class.
if (pointer) fBranchPointer = pointer;
// create sub branches if requested by splitlevel
if (splitlevel > 0) {
const char* elem_type = element->GetTypeName();
fSTLtype = TMath::Abs(TClassEdit::IsSTLCont(elem_type));
TClass *clm;
if (element->CannotSplit()) {
//printf("element: %s/%s will not be split\n",element->GetName(),element->GetTitle());
fSplitLevel = 0;
} else if (element->IsA() == TStreamerBase::Class()) {
// ===> develop the base class
fType = 1;
clm = gROOT->GetClass(element->GetName());
Int_t nbranches = fBranches.GetEntriesFast();
if (!strcmp(name,clm->GetName())) Unroll("",cl,clm,basketsize,splitlevel,0);
else Unroll(name,clm,clm,basketsize,splitlevel,0);
if (!strcmp(name,clm->GetName())) return;
if (strchr(bname,'.')) return;
if (nbranches == fBranches.GetEntriesFast()) {
if (strlen(bname)) sprintf(name,"%s.%s",bname,clm->GetName());
else sprintf(name,"%s",clm->GetName());
SetName(name);
SetTitle(name);
}
return;
} else if (!strcmp(elem_type,"TClonesArray") || !strcmp(elem_type,"TClonesArray*")) {
Bool_t ispointer = !strcmp(elem_type,"TClonesArray*");
TClonesArray *clones;
if (ispointer) {
char **ppointer = (char**)(pointer);
clones = (TClonesArray*)(*ppointer);
} else {
clones = (TClonesArray*)pointer;
}
basket->DeleteEntryOffset(); //entryoffset not required for the clonesarray counter
fEntryOffsetLen = 0;
if (!clones) return;
clm = clones->GetClass();
if (!clm) return;
// ===> Create a leafcount
TLeaf *leaf = new TLeafElement(name,fID, fStreamerType);
leaf->SetBranch(this);
fNleaves = 1;
fLeaves.Add(leaf);
fTree->GetListOfLeaves()->Add(leaf);
// Create a basket for the leafcount
TBasket *basket2 = new TBasket(name,fTree->GetName(),this);
fBaskets.Add(basket2);
// ===> create sub branches for each data member of a TClonesArray
fType = 3;
//check that the contained objects class name is part of the element title
//This name is mandatory when reading the Tree later on and
//the parent class with the pointer to the TClonesArray is not available.
//This info will be used by TStreamerInfo::New
fClonesName = clm->GetName();
char aname[100];
sprintf(aname," (%s)",clm->GetName());
TString atitle = element->GetTitle();
if (!atitle.Contains(aname)) {
atitle += aname;
element->SetTitle(atitle.Data());
}
char branchname[kMaxLen];
sprintf(branchname,"%s_",name);
SetTitle(branchname);
leaf->SetName(branchname);
leaf->SetTitle(branchname);
Unroll(name,clm,clm,basketsize,splitlevel,31);
BuildTitle(name);
return;
} else if ( (fSTLtype>= TClassEdit::kVector && fSTLtype<= TClassEdit::kMultiSet) ||
(fSTLtype>=-TClassEdit::kMultiSet && fSTLtype<=-TClassEdit::kVector) ) {
// case of vector<>, list<> deque<>, set<>, multiset<>
TClass *contCl = gROOT->GetClass(elem_type);
fCollProxy = contCl->GetCollectionProxy()->Generate();
clm = fCollProxy->GetValueClass();
// See if we can split:
Bool_t cansplit = kTRUE;
if (clm==0) {
cansplit = kFALSE;
} else if (clm==TString::Class() || clm==gROOT->GetClass("string")) {
cansplit = kFALSE;
} else if (fCollProxy->HasPointers()) {
cansplit = kFALSE;
} else if ( !clm->CanSplit() ) {
cansplit = kFALSE;
} else if ( clm->GetCollectionProxy() != 0 ) {
// A collection was stored in a collection, we do not know how to split it.
cansplit = kFALSE;
}
// ===> Create a leafcount
if (cansplit) {
TLeaf *leaf = new TLeafElement(name,fID, fStreamerType);
leaf->SetBranch(this);
fNleaves = 1;
fLeaves.Add(leaf);
fTree->GetListOfLeaves()->Add(leaf);
// Create a basket for the leafcount
TBasket *basket2 = new TBasket(name,fTree->GetName(),this);
fBaskets.Add(basket2);
// ===> create sub branches for each data member of a TClonesArray
fType = 4;
//check that the contained objects class name is part of the element title
//This name is mandatory when reading the Tree later on and
//the parent class with the pointer to the TClonesArray is not available.
//This info will be used by TStreamerInfo::New
fClonesName = clm->GetName();
char aname[100];
sprintf(aname," (%s)",clm->GetName());
TString atitle = element->GetTitle();
if (!atitle.Contains(aname)) {
atitle += aname;
element->SetTitle(atitle.Data());
}
char branchname[kMaxLen];
sprintf(branchname,"%s_",name);
SetTitle(branchname);
leaf->SetName(branchname);
leaf->SetTitle(branchname);
Unroll(name,clm,clm,basketsize,splitlevel,41);
BuildTitle(name);
return;
}
} else if (!strchr(elem_type,'*') &&
(fStreamerType == TStreamerInfo::kObject || fStreamerType == TStreamerInfo::kAny)) {
// ===> create sub branches for members that are classes
fType = 2;
clm = gROOT->GetClass(elem_type);
if (Unroll(name,clm,clm,basketsize,splitlevel,0) >= 0) return;
}
}
TLeaf *leaf = new TLeafElement(GetTitle(),fID, fStreamerType);
leaf->SetTitle(GetTitle());
leaf->SetBranch(this);
fNleaves = 1;
fLeaves.Add(leaf);
gTree->GetListOfLeaves()->Add(leaf);
if (brcount) SetBranchCount(brcount);
}
//______________________________________________________________________________
TBranchElement::TBranchElement(const char *bname, TClonesArray *clones, Int_t basketsize, Int_t splitlevel, Int_t compress)
:TBranch(), fInfo(TClonesArray::Class()->GetStreamerInfo()),
fCurrentClass(),fParentClass(), fBranchClass(fInfo->GetClass())
{
// Create a BranchElement
//
// If splitlevel > 0 this branch in turn is split into sub branches
fCollProxy = 0;
fSplitLevel = splitlevel;
fID = 0;
fInit = kTRUE;
fStreamerType = -1;
fType = 0;
fClassVersion = TClonesArray::Class()->GetClassVersion();
fCheckSum = fInfo->GetCheckSum();
fBranchCount = 0;
fBranchCount2 = 0;
fObject = 0;
fBranchPointer = 0;
fMaximum = 0;
fBranchOffset = 0;
fParentOffset = 0;
fBranchTypes = 0;
fSTLtype = TClassEdit::kNotSTL;
fInitOffsets = kFALSE;
fTree = gTree;
fDirectory = fTree->GetDirectory();
fFileName = "";
SetName(bname);
const char* name = GetName();
SetTitle(name);
fClassName = fInfo->GetName();
fCompress = compress;
if (compress == -1 && fTree->GetDirectory()) {
TFile *bfile = fTree->GetDirectory()->GetFile();
if (bfile) fCompress = bfile->GetCompressionLevel();
}
if (basketsize < 100) basketsize = 100;
fBasketSize = basketsize;
fBasketBytes = new Int_t[fMaxBaskets];
fBasketEntry = new Long64_t[fMaxBaskets];
fBasketSeek = new Long64_t[fMaxBaskets];
for (Int_t i=0;i<fMaxBaskets;i++) {
fBasketBytes[i] = 0;
fBasketEntry[i] = 0;
fBasketSeek[i] = 0;
}
// Create a basket for the terminal branch
TBasket *basket = new TBasket(name,fTree->GetName(),this);
fBaskets.Add(basket);
// Set the bit kAutoDelete to specify that when reading
// the object should be deleted before calling Streamer.
// It is foreseen to not set this bit in a future version.
//SetAutoDelete(kTRUE);
SetAutoDelete(kFALSE);
// create sub branches if requested by splitlevel
if (splitlevel > 0) {
// ===> Create a leafcount
TLeaf *leaf = new TLeafElement(name,fID, fStreamerType);
leaf->SetBranch(this);
fNleaves = 1;
fLeaves.Add(leaf);
fTree->GetListOfLeaves()->Add(leaf);
// Create a basket for the leafcount
TBasket *basket = new TBasket(name,fTree->GetName(),this);
fBaskets.Add(basket);
// ===> create sub branches for each data member of a TClonesArray
fType = 3;
TClass *clm = clones->GetClass();
if (!clm) return;
fClonesName = clm->GetName();
std::string branchname = name + std::string("_");
SetTitle(branchname.c_str());
leaf->SetName(branchname.c_str());
leaf->SetTitle(branchname.c_str());
Unroll(name,clm,clm,basketsize,splitlevel,31);
BuildTitle(name);
return;
}
SetBit(kBranchObject);
TLeaf *leaf = new TLeafElement(GetTitle(),fID, fStreamerType);
leaf->SetTitle(GetTitle());
leaf->SetBranch(this);
fNleaves = 1;
fLeaves.Add(leaf);
gTree->GetListOfLeaves()->Add(leaf);
}
//______________________________________________________________________________
TBranchElement::TBranchElement(const char *bname, TVirtualCollectionProxy *cont, Int_t basketsize, Int_t splitlevel, Int_t compress)
: TBranch(),fCurrentClass(),fParentClass(), fBranchClass(cont->GetCollectionClass())
{
// Create a BranchElement
//
// If splitlevel > 0 this branch in turn is split into sub branches
fCollProxy = cont->Generate();
char name[kMaxLen];
strcpy(name,bname);
if (name[strlen(name)-1]=='.') name[strlen(name)-1]=0;
fInitOffsets = kFALSE;
fSplitLevel = splitlevel;
fInfo = 0;
fID = -1;
fInit = kTRUE;
fStreamerType = -1; // TStreamerInfo::kSTLp;
fType = 0;
fClassVersion = cont->GetCollectionClass()->GetClassVersion();
fBranchCount = 0;
fBranchCount2 = 0;
fObject = 0;
fBranchPointer = 0;
fMaximum = 0;
fBranchOffset = 0;
fParentOffset = 0;
fBranchTypes = 0;
fSTLtype = TClassEdit::kNotSTL;
fTree = gTree;
fDirectory = fTree->GetDirectory();
fFileName = "";
SetName(name);
SetTitle(name);
//Bool_t Implemented=kFALSE;
//Assert(Implemented);
fClassName = fBranchClass->GetName();
fCompress = compress;
if (compress == -1 && fTree->GetDirectory()) {
TFile *bfile = fTree->GetDirectory()->GetFile();
if (bfile) fCompress = bfile->GetCompressionLevel();
}
if (basketsize < 100) basketsize = 100;
fBasketSize = basketsize;
fBasketBytes = new Int_t[fMaxBaskets];
fBasketEntry = new Long64_t[fMaxBaskets];
fBasketSeek = new Long64_t[fMaxBaskets];
fBasketEntry[0] = fEntryNumber;
fBasketBytes[0] = 0;
// Create a basket for the terminal branch
TBasket *basket = new TBasket(name,fTree->GetName(),this);
fBaskets.Add(basket);
// Set the bit kAutoDelete to specify that when reading
// the object should be deleted before calling Streamer.
// It is foreseen to not set this bit in a future version.
//SetAutoDelete(kTRUE);
SetAutoDelete(kFALSE);
// create sub branches if requested by splitlevel
if (splitlevel > 0 && fBranchClass->CanSplit()) {
// ===> Create a leafcount
TLeaf *leaf = new TLeafElement(name,fID, fStreamerType);
leaf->SetBranch(this);
fNleaves = 1;
fLeaves.Add(leaf);
fTree->GetListOfLeaves()->Add(leaf);
// Create a basket for the leafcount
TBasket *basket = new TBasket(name,fTree->GetName(),this);
fBaskets.Add(basket);
// ===> create sub branches for each data member of a TSTLCont
fType = 4;
TClass *clm = cont->GetValueClass();
if (!clm) return;
fClonesName = clm->GetName();
char branchname[kMaxLen];
sprintf(branchname,"%s_",name);
SetTitle(branchname);
leaf->SetName(branchname);
leaf->SetTitle(branchname);
Unroll(name,clm,clm,basketsize,splitlevel,41);
BuildTitle(name);
return;
}
TLeaf *leaf = new TLeafElement(GetTitle(),fID, fStreamerType);
leaf->SetTitle(GetTitle());
leaf->SetBranch(this);
fNleaves = 1;
fLeaves.Add(leaf);
gTree->GetListOfLeaves()->Add(leaf);
}
//______________________________________________________________________________
TBranchElement::~TBranchElement()
{
//*-*-*-*-*-*Default destructor for a BranchElement*-*-*-*-*-*-*-*-*-*-*-*
//*-* =====================================
if ( fType==4 ) delete fCollProxy;
if ( fBranchOffset ) delete [] fBranchOffset;
if ( fBranchTypes ) delete [] fBranchTypes;
fCollProxy=0;
fBranches.Delete();
//SetAddress may have allocated an object. Must delete it
if (TestBit(kDeleteObject)) {
if (fObject) {
//TObject *obj = (TObject*)fObject;
// objects of emulated classes allocated in SetAddress should be deleted
//printf("deleting fObject=%x of class: %s, branch: %s, fAddress=%x\n",obj,fClassName.Data(),GetName(),fAddress);
//delete obj;
}
}
}
//______________________________________________________________________________
TBranch *TBranchElement::Branch(const char *subname, void *address, const char *leaflist,Int_t bufsize)
{
// Create a sub-branch of this branch (simple variable case)
// ==================================
//
// This Branch constructor is provided to support non-objects in
// a Tree. The variables described in leaflist may be simple variables
// or structures.
// See the two following constructors for writing objects in a Tree.
//
// By default the branch buffers are stored in the same file as the Tree.
// use TBranch::SetFile to specify a different file
gTree = fTree;
std::string name(GetName()+std::string(".")+subname);
TBranch *branch = new TBranch(name.c_str(),address,leaflist,bufsize);
if (branch->IsZombie()) {
delete branch;
return 0;
}
TLeaf *leaf;
TIter next(branch->GetListOfLeaves());
while ((leaf = (TLeaf*)next())) {
std::string name(GetName()+std::string(".")+leaf->GetName());
leaf->SetName(name.c_str());
}
fBranches.Add(branch);
return branch;
}
//______________________________________________________________________________
Int_t TBranchElement::Branch(const char *foldername, Int_t bufsize, Int_t splitlevel)
{
// This function creates one sub-branch for each element in the folder.
// The function returns the total number of branches created.
TObject *ob = gROOT->FindObjectAny(foldername);
if (!ob) return 0;
if (ob->IsA() != TFolder::Class()) return 0;
Int_t nbranches = GetListOfBranches()->GetEntries();
TFolder *folder = (TFolder*)ob;
TIter next(folder->GetListOfFolders());
TObject *obj;
char occur[20];
while ((obj=next())) {
std::string curname(foldername+std::string("/")+obj->GetName());
if (obj->IsA() == TFolder::Class()) {
Branch(curname.c_str(), bufsize, splitlevel-1);
} else {
void *add = (void*)folder->GetListOfFolders()->GetObjectRef(obj);
for (size_t i=curname.find('/'); i != std::string::npos; i=curname.find('/')) {
curname[i] = '.';
}
Int_t noccur = folder->Occurence(obj);
if (noccur > 0) {
sprintf(occur,"_%d",noccur);
curname += occur;
}
TBranchElement *br;
br = (TBranchElement*)Branch(curname.c_str(),obj->ClassName(), add, bufsize, splitlevel-1);
br->SetBranchFolder();
}
}
return GetListOfBranches()->GetEntries() - nbranches;
}
//______________________________________________________________________________
TBranch *TBranchElement::Branch(const char *subname, const char *classname, void *add, Int_t bufsize, Int_t splitlevel)
{
// Create a sub-branch of this branch (with a class)
// ==================================
//
// Build a TBranchElement for an object of class classname.
// addobj is the address of a pointer to an object of class classname.
// The class dictionary must be available (ClassDef in class header).
//
// This option requires access to the library where the corresponding class
// is defined. Accessing one single data member in the object implies
// reading the full object.
//
// By default the branch buffers are stored in the same file as the parent branch.
// use TBranch::SetFile to specify a different file
//
// see IMPORTANT NOTE about branch names in TTree::Bronch
//
// Use splitlevel < 0 instead of splitlevel=0 when the class
// has a custom Streamer
gTree = fTree;
TClass *cl = gROOT->GetClass(classname);
if (!cl) {
Error("Branch","Cannot find class:%s",classname);
return 0;
}
//if splitlevel <= 0 and class has a custom Streamer, we must create
//a TBranchObject. We cannot assume that TClass::ReadBuffer is consistent
//with the custom Streamer. The penalty is that one cannot process
//this Tree without the class library containing the class.
//The following convention is used for the RootFlag
// #pragma link C++ class TExMap; rootflag = 0
// #pragma link C++ class TList-; rootflag = 1
// #pragma link C++ class TArray!; rootflag = 2
// #pragma link C++ class TArrayC-!; rootflag = 3
// #pragma link C++ class TBits+; rootflag = 4
// #pragma link C++ class Txxxx+!; rootflag = 6
char **ppointer = (char**)add;
char *objadd = *ppointer;
std::string name(GetName()+std::string(".")+subname);
if (cl == TClonesArray::Class()) {
TClonesArray *clones = (TClonesArray *)objadd;
if (!clones) {
Error("Branch","Pointer to TClonesArray is null");
return 0;
}
if (!clones->GetClass()) {
Error("Branch","TClonesArray with no class defined in branch: %s",name.c_str());
return 0;
}
G__ClassInfo *classinfo = clones->GetClass()->GetClassInfo();
if (!classinfo) {
Error("Bronch","TClonesArray with no dictionary defined in branch: %s",name.c_str());
return 0;
}
if (splitlevel > 0) {
if (classinfo->RootFlag() & 1)
Warning("Branch","Using split mode on a class: %s with a custom Streamer",clones->GetClass()->GetName());
} else {
if (classinfo->RootFlag() & 1) clones->BypassStreamer(kFALSE);
TBranchObject *branch = new TBranchObject(name.c_str(),classname,add,bufsize,0);
fBranches.Add(branch);
return branch;
}
}
Bool_t hasCustomStreamer = kFALSE;
if (!cl->GetClassInfo()) {
Error("Branch","Cannot find dictionary for class: %s",classname);
return 0;
}
if (cl->GetClassInfo()->RootFlag() & 1) hasCustomStreamer = kTRUE;
if (splitlevel < 0 || (splitlevel == 0 && hasCustomStreamer)) {
TBranchObject *branch = new TBranchObject(name.c_str(),classname,add,bufsize,0);
fBranches.Add(branch);
return branch;
}
//hopefully normal case
Bool_t delobj = kFALSE;
//====> special case of TClonesArray
if(cl == TClonesArray::Class()) {
TBranchElement *branch = new TBranchElement(name.c_str(),(TClonesArray*)objadd,bufsize,splitlevel);
fBranches.Add(branch);
branch->SetAddress(add);
return branch;
}
//====>
if (!objadd) {
objadd = (char*)cl->New();
*ppointer = objadd;
delobj = kTRUE;
}
//build the StreamerInfo if first time for the class
Bool_t optim = TStreamerInfo::CanOptimize();
if (splitlevel > 0) TStreamerInfo::Optimize(kFALSE);
TStreamerInfo *sinfo = fTree->BuildStreamerInfo(cl,objadd);
TStreamerInfo::Optimize(optim);
// create a dummy top level branch object
Int_t id = -1;
if (splitlevel > 0) id = -2;
size_t dot = name.find('.');
size_t nch = name.length();
Bool_t dotlast = kFALSE;
if (nch && name[nch-1] == '.') dotlast = kTRUE;
TBranchElement *branch = new TBranchElement(name.c_str(),sinfo,id,objadd,bufsize,splitlevel);
fBranches.Add(branch);
if (splitlevel > 0) {
// Loop on all public data members of the class and its base classes
TObjArray *blist = branch->GetListOfBranches();
TIter next(sinfo->GetElements());
TStreamerElement *element;
id = 0;
while ((element = (TStreamerElement*)next())) {
std::string bname(name);
char *pointer = (char*)objadd + element->GetOffset();
Bool_t isBase = element->IsA() == TStreamerBase::Class();
if (isBase) {
TClass *clbase = element->GetClassPointer();
if (clbase == TObject::Class() && cl->CanIgnoreTObjectStreamer()) continue;
}
if ( dot != std::string::npos ) {
if (dotlast) {
bname += element->GetFullName();
} else if ( !isBase) {
bname += ".";
bname += element->GetFullName();
}
} else {
bname = element->GetFullName();
}
TBranchElement *bre = new TBranchElement(bname.c_str(),sinfo,id,pointer,bufsize,splitlevel-1);
blist->Add(bre);
id++;
}
}
branch->SetAddress(add);
if (delobj) {delete objadd; *ppointer=0;}
return branch;
}
//______________________________________________________________________________
void TBranchElement::Browse(TBrowser *b)
{
Int_t nbranches = fBranches.GetEntriesFast();
if (nbranches > 0) {
TList persistentBranches;
TBranch* branch=0;
TIter iB(&fBranches);
while((branch=(TBranch*)iB())) {
if (branch->IsFolder()) persistentBranches.Add(branch);
else {
// only show branches corresponding to persistent members
TClass* cl=0;
if (strlen(GetClonesName()))
// this works both for top level branches and for sub-branches,
// as GetClonesName() is properly updated for sub-branches
cl=gROOT->GetClass(GetClonesName());
else {
cl=gROOT->GetClass(GetClassName());
// check if we're in a sub-branch of this class
// we can only find out asking the streamer given our ID
ULong_t *elems=0;
TStreamerElement *element=0;
TClass* clsub=0;
if (fID>=0 && GetInfo()
&& ((elems=GetInfo()->GetElems()))
&& ((element=(TStreamerElement *)elems[fID]))
&& ((clsub=element->GetClassPointer())))
cl=clsub;
}
if (cl) {
TString strMember=branch->GetName();
Size_t mempos=strMember.Last('.');
if (mempos!=kNPOS)
strMember.Remove(0, (Int_t)mempos+1);
mempos=strMember.First('[');
if (mempos!=kNPOS)
strMember.Remove((Int_t)mempos);
TDataMember* m=cl->GetDataMember(strMember);
if (!m || m->IsPersistent()) persistentBranches.Add(branch);
} else persistentBranches.Add(branch);
} // branch if not a folder
}
persistentBranches.Browse(b);
// add all public const methods without params
if (GetBrowsables() && GetBrowsables()->GetSize())
GetBrowsables()->Browse(b);
} else {
if (GetBrowsables() && GetBrowsables()->GetSize()) {
GetBrowsables()->Browse(b);
return;
}
// Get the name and strip any extra brackets
// in order to get the full arrays.
TString slash("/"), escapedSlash("\\/");
TString name = GetName();
Int_t pos = name.First('[');
if (pos!=kNPOS) name.Remove(pos);
TString mothername;
if (GetMother()) {
mothername = GetMother()->GetName();
pos = mothername.First('[');
if (pos!=kNPOS) mothername.Remove(pos);
Int_t len = mothername.Length();
if (len) {
if (mothername(len-1)!='.') {
// We do not know for sure whether the mother's name is
// already preprended. So we need to check:
// a) it is prepended
// b) it is NOT the name of a daugher (i.e. mothername.mothername exist)
TString doublename = mothername;
doublename.Append(".");
Int_t isthere = (name.Index(doublename)==0);
if (!isthere) {
name.Prepend(doublename);
} else {
if (GetMother()->FindBranch(mothername)) {
doublename.Append(mothername);
isthere = (name.Index(doublename)==0);
if (!isthere) {
mothername.Append(".");
name.Prepend(mothername);
}
} else {
// Nothing to do because the mother's name is
// already in the name.
}
}
} else {
// If the mother's name end with a dot then
// the daughter probably already contains the mother's name
if (name.Index(mothername)==kNPOS) {
name.Prepend(mothername);
}
}
}
}
name.ReplaceAll(slash, escapedSlash);
GetTree()->Draw(name, "", b ? b->GetDrawOption() : "");
if (gPad) gPad->Update();
}
}
//______________________________________________________________________________
void TBranchElement::BuildTitle(const char *name)
{
//set branch/leaf name/title in case of a TClonesArray sub-branch
char branchname[kMaxLen];
Int_t nbranches = fBranches.GetEntries();
for (Int_t i=0;i<nbranches;i++) {
TBranchElement *bre = (TBranchElement*)fBranches.At(i);
Assert(fType==3 || fType==4 );
bre->SetType(fType*10+1);
bre->fCollProxy = GetCollectionProxy();
bre->BuildTitle(name);
const char *fin = strrchr(bre->GetTitle(),'.');
if (fin == 0) continue;
bre->SetBranchCount(this); //primary branchcount
TLeafElement *lf = (TLeafElement*)bre->GetListOfLeaves()->At(0);
//if branch name is of the form fTracks.fCovar[3][4]
//set the title to fCovar[fTracks_]
strcpy(branchname,fin+1);
char *dim = (char*)strstr(branchname,"[");
Int_t nch = strlen(branchname);
if (dim) {
*dim = 0;
nch = dim-branchname;
}
sprintf(branchname+nch,"[%s_]",name);
bre->SetTitle(branchname);
if (lf) lf->SetTitle(branchname);
// is there a secondary branchcount ?
//fBranchCount2 points to the secondary branchcount
//in case a TClonesArray element has itself a branchcount.
//Example in Event class with TClonesArray fTracks of Track objects.
//if the Track object has two members
// Int_t fNpoint;
// Float_t *fPoints; //[fNpoint]
//In this case the TBranchElement fTracks.fPoints has
// -its primary branchcount pointing to the branch fTracks
// -its secondary branchcount pointing to fTracks.fNpoint
Int_t stype = bre->GetStreamerType();
if (stype > 40 && stype < 55) {
char name2[kMaxLen];
strcpy(name2,bre->GetName());
char *bn = strrchr(name2,'.');
if (!bn) continue;
TStreamerBasicPointer *el = (TStreamerBasicPointer*)bre->GetInfo()->GetElements()->FindObject(bn+1);
strcpy(bn+1,el->GetCountName());
TBranchElement *bc2 = (TBranchElement*)fBranches.FindObject(name2);
bre->SetBranchCount2(bc2);
//printf("Branch:%s has a secondary branchcount, bc2=%s\n",bre->GetName(),bc2->GetName());
}
}
}
//______________________________________________________________________________
Int_t TBranchElement::Fill()
{
//*-*-*-*-*-*-*-*Loop on all leaves of this branch to fill Basket buffer*-*-*
//*-* =======================================================
//
// The function returns the number of bytes committed to the
// individual branch(es).
// If a write error occurs, the number of bytes returned is -1.
// If no data are written, because e.g. the branch is disabled,
// the number of bytes returned is 0.
//
Int_t nbytes = 0, nwrite = 0, nerror = 0;
Int_t nbranches = fBranches.GetEntriesFast();
// update addresses if top level branch
if (fID < 0) {
if (!fAddress) {
Error("Fill","attempt to fill branch %s while addresss is not set",GetName());
return 0;
}
void *add1 = fObject;
void **add2 = (void**)fAddress;
if (add1 != *add2) {
SetAddress(fAddress);
}
}
//if the tree has a TRefTable, set the current branch if branch is not a basic type
if (fType > 0 && fType < 10) {
TBranchRef *bref = fTree->GetBranchRef();
if (bref) bref->SetParent(this);
}
if (nbranches) {
if (fType == 3 || fType == 4) {
nbytes += (nwrite = TBranch::Fill()); //TClonesArray counter
if ( nwrite < 0 ) {
Error("Fill","Failed filling branch:%s, nbytes=%d",GetName(),nwrite);
nerror++;
}
}
else {
fEntries++;
}
for (Int_t i=0;i<nbranches;i++) {
TBranchElement *branch = (TBranchElement*)fBranches[i];
if (!branch->TestBit(kDoNotProcess)) {
nbytes += (nwrite = branch->Fill());
if ( nwrite < 0 ) {
Error("Fill","Failed filling branch:%s.%s, nbytes=%d",GetName(),branch->GetName(),nwrite);
nerror++;
}
}
}
} else {
if (!TestBit(kDoNotProcess)) {
nbytes += (nwrite = TBranch::Fill());
if ( nwrite < 0 ) {
Error("Fill","Failed filling branch:%s, nbytes=%d",GetName(),nwrite);
nerror++;
}
}
}
if (fTree->Debug() > 0) {
Long64_t entry = fEntries;
if (entry >= fTree->GetDebugMin() && entry <= fTree->GetDebugMax()) {
printf("Fill: %lld, branch=%s, nbytes=%d\n",entry,GetName(),nbytes);
}
}
return nerror==0 ? nbytes : -1;
}
//______________________________________________________________________________
void TBranchElement::FillLeaves(TBuffer &b)
{
// Fill buffers of this branch
if (!fObject) return;
if (fType <= 2 && TestBit(kBranchObject)) b.MapObject((TObject*)fObject);
if (fType == 4) { // STL vector/list of objects
if (!fObject) {
b << 0;
} else {
TVirtualCollectionProxy::TPushPop helper(GetCollectionProxy(),fObject);
Int_t n = fCollProxy->Size();
if (n > fMaximum) fMaximum = n;
b << n;
}
} else if (fType == 41) { // sub branch of an STL class
//char **ppointer = (char**)fAddress;
if (!fObject) return;
TVirtualCollectionProxy::TPushPop helper(GetCollectionProxy(),fObject);// NOTE: this wont work if a pointer to vector is split!
Int_t n = fCollProxy->Size();
fInfo->WriteBufferSTL(b,fCollProxy,n,fID,fOffset);
} else if (fType == 3) { //top level branch of a TClonesArray
if (fTree->GetMakeClass()) {
TClass *cl = gROOT->GetClass(GetClonesName());
cl->GetStreamerInfo()->ForceWriteInfo((TFile *)b.GetParent());
Int_t *n = (Int_t*)fAddress;
b << *n;
return;
}
TClonesArray *clones = (TClonesArray*)fObject;
if (!clones) {
b << 0;
} else {
Int_t n = clones->GetEntriesFast();
if (n > fMaximum) fMaximum = n;
b << n;
}
} else if (fType == 31) { // sub branch of a TClonesArray
if (fTree->GetMakeClass()) {
Int_t atype = fStreamerType;
if (atype > 54) return;
if (!fAddress) return;
Int_t *nn = (Int_t*)fBranchCount->GetAddress();
Int_t n = *nn;
if (atype>40) {
printf("Clonesa: %s, n=%d, sorry not supported yet\n",GetName(),n);
}
if (atype > 20) {
atype -= 20;
TLeafElement *leaf = (TLeafElement*)fLeaves.UncheckedAt(0);
n *= leaf->GetLenStatic();
}
switch (atype) {
case 1: {b.WriteFastArray((Char_t*) fAddress, n); break;}
case 2: {b.WriteFastArray((Short_t*) fAddress, n); break;}
case 3: {b.WriteFastArray((Int_t*) fAddress, n); break;}
case 4: {b.WriteFastArray((Long_t*) fAddress, n); break;}
case 5: {b.WriteFastArray((Float_t*) fAddress, n); break;}
case 6: {b.WriteFastArray((Int_t*) fAddress, n); break;}
case 8: {b.WriteFastArray((Double_t*) fAddress, n); break;}
case 11: {b.WriteFastArray((UChar_t*) fAddress, n); break;}
case 12: {b.WriteFastArray((UShort_t*) fAddress, n); break;}
case 13: {b.WriteFastArray((UInt_t*) fAddress, n); break;}
case 14: {b.WriteFastArray((ULong_t*) fAddress, n); break;}
case 15: {b.WriteFastArray((UInt_t*) fAddress, n); break;}
case 16: {b.WriteFastArray((Long64_t*) fAddress, n); break;}
case 17: {b.WriteFastArray((ULong64_t*)fAddress, n); break;}
case 18: {b.WriteFastArray((Bool_t*) fAddress, n); break;}
case 9: {Double_t *xx = (Double_t*)fAddress;
for (Int_t ii=0;ii<n;ii++) b << (Float_t)xx[ii];
break;}
}
return;
}
TClonesArray *clones = (TClonesArray*)fObject;
if (!clones) return;
Int_t n = clones->GetEntriesFast();
fInfo->WriteBufferClones(b,clones,n,fID,fOffset);
} else if (fType <= 2) {
Int_t n = fInfo->WriteBufferAux(b,&fObject,fID,1,0,0); // NOTE: expanded
if (fStreamerType == 6) {
if (n > fMaximum) fMaximum = n;
}
}
}
//______________________________________________________________________________
Int_t TBranchElement::GetDataMemberOffset(const TClass *cl, const char *name)
{
// This function is for internal use only!
// Return the offset if 'name' is found in the list of real data for cl
// Output an error message if the 'name' is NOT found (to prevent reliance on the previous
// implementation.
// The previous implementation of the class had the following comments:
// Return the offset if 'name' is found in the list of real data for cl
// return offset od member name in class cl
// check for the following cases Otto and Axel
//
// Return the opposite of the offset if name is of the form 'XXX.YYY' where
// XXX is a name found in the list of real data for cl
//
// case Otto
// class TUsrSevtData2:public TMrbSubevent_Caen {
// class TMrbSubevent_Caen:public TObject {
// TUsrHitBuffer fHitBuffer;
// class TUsrHitBuffer:public TObject {
// Int_t fHighWater;
// TClonesArray *fHits;
// code below to get the correct address for fHitBuffer.fHits
//
// i.e. this is the case where we have a TClonesArray inside an object
// which is embedded into another (which is stored in a branch)
//
// case Axel
// class jet: public TLorentzVector {
// TClonesArray* caJet=new TClonesArray("jet");
// TTree* tree=new TTree("test","test",99);
// tree->Branch("jet", "TClonesArray",&caJet, 32000);
//
// i.e this is the case where we have an embedded object inside an object
// stored in a TClonesArray
Int_t offset = 0;
TRealData *rd = cl->GetRealData(name);
if (!rd) {
Error("GetDataMemberOffset","obsolete call with (%s,%s)\n",
cl->GetName(),name);
} else {
offset = rd->GetThisOffset();
}
if (gDebug > 3) {
printf("GetDataMemberOffset(%s,%s) => %d\n",
cl->GetName(),name,offset);
}
return offset;
}
//______________________________________________________________________________
void TBranchElement::SetupAddresses()
{
// If the branch address had not yet been set,
// we set all addresses starting with the top level parent branch
// This is requires to be done in order for GetOffset
// to be guarantee correct and for GetEntry to be run.
if (fAddress == 0 && fTree->GetMakeClass() == 0) {
if (TestBit(kDoNotProcess)) return;
TBranchElement *mother = (TBranchElement*)GetMother();
TClass *cl = gROOT->GetClass(mother->GetClassName());
if (fInfo && fInfo->GetOffsets()) fInfo->BuildOld();
if (!mother || !cl) return;
if (!mother->GetAddress()) {
Bool_t motherStatus = mother->TestBit(kDoNotProcess);
mother->ResetBit(kDoNotProcess);
mother->SetAddress(0);
mother->SetBit(kDoNotProcess,motherStatus);
}
}
}
//______________________________________________________________________________
Int_t TBranchElement::GetEntry(Long64_t entry, Int_t getall)
{
//*-*-*-*-*Read all branches of a BranchElement and return total number of bytes
//*-* ====================================================================
// If entry = 0 take current entry number + 1
// If entry < 0 reset entry number to 0
//
// The function returns the number of bytes read from the input buffer.
// If entry does not exist the function returns 0.
// If an I/O error occurs, the function returns -1.
//
// See IMPORTANT REMARKS in TTree::GetEntry
Int_t nbranches = fBranches.GetEntriesFast();
Int_t nbytes = 0;
if (fAddress == 0 && fTree->GetMakeClass() == 0) {
SetupAddresses();
}
if (nbranches) {
//branch has daughters
//one must always read the branch counter.
//In the case when one reads consecutively twice the same entry,
//the user may have cleared the TClonesArray between the 2 GetEntry
if ( fType == 3 || fType == 4 ) {
fReadEntry = entry;
nbytes += TBranch::GetEntry(entry, getall);
}
Int_t i;
switch(fSTLtype) {
case TClassEdit::kSet:
case TClassEdit::kMultiSet:
case TClassEdit::kMap:
case TClassEdit::kMultiMap:
break;
default:
for (i=0;i<nbranches;i++) {
TBranch *branch = (TBranch*)fBranches[i];
Int_t nb = branch->GetEntry(entry, getall);
if (nb < 0) return nb;
nbytes += nb;
}
break;
}
} else {
//terminal branch
if (fBranchCount && fBranchCount->GetReadEntry() != entry) nbytes += fBranchCount->TBranch::GetEntry(entry,getall);
nbytes += TBranch::GetEntry(entry, getall);
}
// if Tree has a TBranchRef, set the ReadEntry in the TBranchRef
TBranchRef *bref = fTree->GetBranchRef();
if (bref) {
bref->SetParent(this);
bref->SetReadEntry(entry);
}
if (fTree->Debug() > 0) {
if (entry >= fTree->GetDebugMin() && entry <= fTree->GetDebugMax()) {
printf("GetEntry: %lld, branch=%s, nbytes=%d\n",entry,GetName(),nbytes);
}
}
return nbytes;
}
//______________________________________________________________________________
const char *TBranchElement::GetIconName() const
{
// Return icon name depending on type of branch element.
if (IsFolder())
return "TBranchElement-folder";
else
return "TBranchElement-leaf";
}
//______________________________________________________________________________
Bool_t TBranchElement::CheckBranchID()
{
// Need to reassign branches in case schema evolution has scrambled leaf list.
if ( GetID() >= 0 ) {
size_t pos;
std::string s( GetName() );
pos = s.rfind('.');
if ( pos != std::string::npos ) {
s = s.substr(pos+1);
}
while ( (pos=s.rfind('[')) != std::string::npos ) {
s = s.substr(0,pos);
}
int offset = 0;
TStreamerElement* elt = fInfo->GetStreamerElement(s.c_str(),offset);
if ( elt ) {
size_t ndata = fInfo->GetNdata();
ULong_t *elems = fInfo->GetElems();
for(size_t i=0; i < ndata; ++i ) {
if ( (TStreamerElement*)elems[i] == elt ) {
fID = i;
break;
}
}
}
else {
// Element may be missing, if data member got removed.
// Warning("CheckBranchID","Cannot find streamer element:%s",s.c_str());
}
}
return kTRUE;
}
//______________________________________________________________________________
TStreamerInfo *TBranchElement::GetInfo()
{
//return pointer to TStreamerinfo object for the class of this branch
//rebuild the info if not yet done
Bool_t optim = TStreamerInfo::CanOptimize();
if (fInfo) {
if (!fInfo->GetOffsets()) {
TStreamerInfo::Optimize(kFALSE);
fInfo->Compile();
TStreamerInfo::Optimize(optim);
}
if (!fInit) fInit = CheckBranchID();
return fInfo;
}
TClass *cl = fBranchClass;
if (cl) {
TStreamerInfo::Optimize(kFALSE);
if (cl == TClonesArray::Class()) fClassVersion = TClonesArray::Class()->GetClassVersion();
fInfo = cl->GetStreamerInfo(fClassVersion);
if (fCheckSum != 0 && (cl->IsForeign() ||
(!cl->IsLoaded() &&
fClassVersion==1 &&
cl->GetStreamerInfos()->At(1)!=0 &&
fCheckSum!= ((TStreamerInfo*)cl->GetStreamerInfos()->At(1))->GetCheckSum()))) {
Int_t ninfos = cl->GetStreamerInfos()->GetEntriesFast();
for (Int_t i=1;i<ninfos;i++) {
TStreamerInfo *info = (TStreamerInfo*)cl->GetStreamerInfos()->At(i);
if (!info) continue;
if (info->GetCheckSum() == fCheckSum) {
fClassVersion = i;
fInfo = cl->GetStreamerInfo(fClassVersion);
break;
}
}
}
if (fInfo && !fInfo->GetOffsets()) {
fInfo->Compile();
}
TStreamerInfo::Optimize(optim);
if ( !fInit ) fInit = CheckBranchID();
}
return fInfo;
}
//______________________________________________________________________________
Int_t TBranchElement::GetMaximum() const
{
// Return maximum count value of the branchcount if any
if (fBranchCount) return fBranchCount->GetMaximum();
return fMaximum;
}
//______________________________________________________________________________
const char *TBranchElement::GetTypeName() const
{
// return type name of element in the branch
if (fType == 3 || fType == 4) {
return "Int_t";
}
if (fStreamerType <=0 || fStreamerType >= 60) return fClassName.Data();
const char *types[19] = {"",
"Char_t","Short_t","Int_t","Long_t","Float_t",
"Int_t","",
"Double_t","Double32_t",
"",
"UChar_t","UShort_t","UInt_t","ULong_t","UInt_t",
"Long64_t","ULong64_t","Bool_t"};
Int_t itype = fStreamerType%20;
return types[itype];
}
//______________________________________________________________________________
Double_t TBranchElement::GetValue(Int_t j, Int_t len, Bool_t subarr) const
{
// Returns branch value. If the leaf is an array, j is the index in the array
// If leaf is an array inside a TClonesArray, len should be the length of the
// array. If subarr is true, then len is actually the index within the sub-array
if (j == 0 && fBranchCount) {
Int_t entry = fTree->GetReadEntry();
fBranchCount->TBranch::GetEntry(entry);
if (fBranchCount2) fBranchCount2->TBranch::GetEntry(entry);
}
if (fTree->GetMakeClass()) {
if (!fAddress) return 0;
if (fType == 3 || fType == 4 ) { //top level branch of a TClonesArray
return (Double_t)fNdata;
} else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
Int_t atype = fStreamerType;
if (atype < 20) atype += 20;
return fInfo->GetValue(fAddress,atype,j,1);
} else if (fType <= 2) { // branch in split mode
if (fStreamerType > 40 && fStreamerType < 55) {
Int_t atype = fStreamerType - 20;
return fInfo->GetValue(fAddress,atype,j,1);
} else {
return fInfo->GetValue(fObject,fID,j,-1);
}
}
}
if (fType == 31) {
TClonesArray *clones = (TClonesArray*)fObject;
if (subarr) return fInfo->GetValueClones(clones,fID, j, len,fOffset);
else return fInfo->GetValueClones(clones,fID, j/len, j%len,fOffset);
} else if (fType == 41) {
TVirtualCollectionProxy::TPushPop helper(fCollProxy,fObject);
if (subarr) return fInfo->GetValueSTL(fCollProxy,fID, j, len,fOffset);
else return fInfo->GetValueSTL(fCollProxy,fID, j/len, j%len,fOffset);
} else {
if (fInfo) return fInfo->GetValue(fObject,fID,j,-1);
return 0;
}
}
//______________________________________________________________________________
void *TBranchElement::GetValuePointer() const
{
// Returns pointer to first data element of this branch
// Currently used only for members of type character
if (fBranchCount) {
Int_t entry = fTree->GetReadEntry();
fBranchCount->TBranch::GetEntry(entry);
if (fBranchCount2) fBranchCount2->TBranch::GetEntry(entry);
}
if (fTree->GetMakeClass()) {
if (!fAddress) return 0;
if (fType == 3) { //top level branch of a TClonesArray
//return &fNdata;
return 0;
} else if (fType == 4) { //top level branch of a TClonesArray
//return &fNdata;
return 0;
} else if (fType == 31) { // sub branch of a TClonesArray
//Int_t atype = fStreamerType;
//if (atype < 20) atype += 20;
//return fInfo->GetValue(fAddress,atype,j,1);
return 0;
} else if (fType == 41) { // sub branch of a TClonesArray
//Int_t atype = fStreamerType;
//if (atype < 20) atype += 20;
//return fInfo->GetValue(fAddress,atype,j,1);
return 0;
} else if (fType <= 2) { // branch in split mode
if (fStreamerType > 40 && fStreamerType < 55) {
//Int_t atype = fStreamerType - 20;
//return fInfo->GetValue(fAddress,atype,j,1);
return 0;
} else {
//return fInfo->GetValue(fObject,fID,j,-1);
return 0;
}
}
}
if (fType == 31) {
//TClonesArray *clones = (TClonesArray*)fObject;
//if (subarr) return fInfo->GetValueClones(clones,fID, j, len,fOffset);
//else return fInfo->GetValueClones(clones,fID, j/len, j%len,fOffset);
return 0;
} else if (fType == 41) {
//TClonesArray *clones = (TClonesArray*)fObject;
//if (subarr) return fInfo->GetValueClones(clones,fID, j, len,fOffset);
//else return fInfo->GetValueClones(clones,fID, j/len, j%len,fOffset);
return 0;
} else {
//return fInfo->GetValue(fObject,fID,j,-1);
if (!fInfo || !fObject) return 0;
char **val = (char**)(fObject+fInfo->GetOffsets()[fID]);
return *val;
}
}
//______________________________________________________________________________
Bool_t TBranchElement::IsFolder() const
{
//*-*-*-*-*Return TRUE if more than one leaf, FALSE otherwise*-*
//*-* ==================================================
Int_t nbranches = fBranches.GetEntriesFast();
if (nbranches >= 1) return kTRUE;
TList* browsables= const_cast<TBranchElement*>(this)->GetBrowsables();
return (browsables && browsables->GetSize());
}
//______________________________________________________________________________
Bool_t TBranchElement::IsMissingCollection() const
{
// In version of ROOT older than 4.00/03, if a collection (TClonesArray
// or stl container) was split but the pointer to the collection was zeroed
// out, nothing was saved. Hence there is no __easy__ way to detect the
// case. In newer version, a zero is inserted so that a 'missing' collection
// appears as an empty collection.
// This function helps in detecting this case so that we can recover nicely.
Bool_t ismissing = kFALSE;
TBasket *basket = (TBasket*)fBaskets.UncheckedAt(fReadBasket);
if (basket && fTree) {
Int_t entry = fTree->GetReadEntry();
Int_t first = fBasketEntry[fReadBasket];
Int_t last;
if (fReadBasket == fWriteBasket) last = fEntryNumber - 1;
else last = fBasketEntry[fReadBasket+1] - 1;
Int_t *entryOffset = basket->GetEntryOffset();
Int_t bufbegin ;
Int_t bufnext;
if (entryOffset) {
bufbegin = entryOffset[entry-first];
if (entry<last) {
bufnext = entryOffset[entry+1-first];
} else {
bufnext = basket->GetLast();
}
if (bufnext==bufbegin) {
ismissing = kTRUE;
} else {
// fixed length buffer so this is not the case here.
if (basket->GetNevBufSize()==0) {
ismissing = kTRUE;
}
}
}
}
return ismissing;
}
//______________________________________________________________________________
void TBranchElement::Print(Option_t *option) const
{
//*-*-*-*-*-*-*-*-*-*-*-*Print TBranch parameters*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ========================
Int_t nbranches = fBranches.GetEntriesFast();
if (nbranches) {
if (fID == -2) {
if (strcmp(GetName(),GetTitle()) == 0) {
Printf("*Branch :%-66s *",GetName());
} else {
Printf("*Branch :%-9s : %-54s *",GetName(),GetTitle());
}
Printf("*Entries : %8d : BranchElement (see below) *",Int_t(fEntries));
Printf("*............................................................................*");
}
if (fType >= 2) {
TBranch::Print(option);
}
for (Int_t i=0;i<nbranches;i++) {
TBranch *branch = (TBranch*)fBranches.At(i);
branch->Print(option);
}
} else {
TBranch::Print(option);
}
}
//______________________________________________________________________________
void TBranchElement::PrintValue(Int_t lenmax) const
{
// Prints leaf value
if (fTree->GetMakeClass()) {
if (!fAddress) return;
if (fType == 3 || fType == 4) { //top level branch of a TClonesArray
printf(" %-15s = %d\n",GetName(),fNdata);
return;
} else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
Int_t n = TMath::Min(10,fNdata);
Int_t atype = fStreamerType+TStreamerInfo::kOffsetL;
// TStreamerInfo::kOffsetL + TStreamerInfo::kChar is printed as a character strings
// and hence could print weird character. So let's do let damage and print an unsigned
// char instead (not perfect but better).
if (fStreamerType==TStreamerInfo::kChar) atype=TStreamerInfo::kOffsetL + TStreamerInfo::kUChar;
if (atype > 54) {
//more logic required here (like in ReadLeaves)
printf(" %-15s = %d\n",GetName(),fNdata);
return;
}
if (fStreamerType > 20) {
atype -= 20;
TLeafElement *leaf = (TLeafElement*)fLeaves.UncheckedAt(0);
n *= leaf->GetLenStatic();
}
if (fInfo) fInfo->PrintValue(GetName(),fAddress,atype,n,lenmax);
return;
} else if (fType <= 2) { // branch in split mode
if (fStreamerType > 40 && fStreamerType < 55) {
Int_t atype = fStreamerType - 20;
Int_t n = (Int_t)((TBranchElement*)fBranchCount)->GetValue(0,0);
if (fInfo) fInfo->PrintValue(GetName(),fAddress,atype,n,lenmax);
} else {
if (fInfo) fInfo->PrintValue(GetName(),fObject,fID,-1,lenmax);
}
return;
}
return;
}
if (fType == 3) {
printf(" %-15s = %d\n",GetName(),fNdata);
} else if (fType == 31) {
TClonesArray *clones = (TClonesArray*)fObject;
if (fInfo) fInfo->PrintValueClones(GetName(),clones,fID,fOffset,lenmax);
} else if (fType == 41) {
TVirtualCollectionProxy::TPushPop helper(fCollProxy,fObject); // Object);
if (fInfo) fInfo->PrintValueSTL(GetName(),fCollProxy,fID,fOffset,lenmax);
} else {
if (fInfo) fInfo->PrintValue(GetName(),fObject,fID,-1,lenmax);
}
}
//______________________________________________________________________________
void TBranchElement::ReadLeaves(TBuffer &b)
{
// Read buffers for this branch
if (fTree->GetMakeClass()) {
if (fType == 3 || fType == 4) { //top level branch of a TClonesArray
Int_t *n = (Int_t*)fAddress;
b >> n[0];
if (n[0]<0 || n[0]>fMaximum) {
if (IsMissingCollection()) {
n[0] = 0;
b.SetBufferOffset( b.Length() - sizeof(n) );
} else {
Error("ReadLeaves",
"Incorrect size read for the container in %s\nThe size read is %d when the maximum is %d\nThe size is reset to 0 for this entry (%d)",
GetName(),n,fMaximum,GetReadEntry());
n[0] = 0;
}
}
fNdata = n[0];
if ( fType == 4) {
Int_t i, nbranches = fBranches.GetEntriesFast();
switch(fSTLtype) {
case TClassEdit::kSet:
case TClassEdit::kMultiSet:
case TClassEdit::kMap:
case TClassEdit::kMultiMap:
for (i=0;i<nbranches;i++) {
TBranch *branch = (TBranch*)fBranches[i];
Int_t nb = branch->GetEntry(GetReadEntry(), 1);
if (nb < 0) break;
}
break;
default:
break;
}
}
return;
} else if (fType == 31 || fType == 41) { // sub branch of a TClonesArray
fNdata = fBranchCount->GetNdata();
Int_t atype = fStreamerType;
if (atype > 54) return;
if (!fAddress) return;
Int_t n = fNdata;
if (atype>40) {
atype -= 40;
if (!fBranchCount2) return;
const char *len_where = (char*)fBranchCount2->fAddress;
if (!len_where) return;
Int_t len_atype = fBranchCount2->fStreamerType;
Int_t length;
Int_t k;
Char_t isArray;
for( k=0; k<n; k++) {
char **where = &(((char**)fAddress)[k]);
delete [] *where;
*where = 0;
switch(len_atype) {
case 1: {length = ((Char_t*) len_where)[k]; break;}
case 2: {length = ((Short_t*) len_where)[k]; break;}
case 3: {length = ((Int_t*) len_where)[k]; break;}
case 4: {length = ((Long_t*) len_where)[k]; break;}
//case 5: {length = ((Float_t*) len_where)[k]; break;}
case 6: {length = ((Int_t*) len_where)[k]; break;}
//case 8: {length = ((Double_t*)len_where)[k]; break;}
case 11: {length = ((UChar_t*) len_where)[k]; break;}
case 12: {length = ((UShort_t*) len_where)[k]; break;}
case 13: {length = ((UInt_t*) len_where)[k]; break;}
case 14: {length = ((ULong_t*) len_where)[k]; break;}
case 15: {length = ((UInt_t*) len_where)[k]; break;}
case 16: {length = ((Long64_t*) len_where)[k]; break;}
case 17: {length = ((ULong64_t*)len_where)[k]; break;}
case 18: {length = ((Bool_t*) len_where)[k]; break;}
default: continue;
}
b >> isArray;
if (length <= 0) continue;
if (isArray == 0) continue;
switch (atype) {
case 1: {*where=new char[sizeof(Char_t)*length]; b.ReadFastArray((Char_t*) *where, length); break;}
case 2: {*where=new char[sizeof(Short_t)*length]; b.ReadFastArray((Short_t*) *where, length); break;}
case 3: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
case 4: {*where=new char[sizeof(Long_t)*length]; b.ReadFastArray((Long_t*) *where, length); break;}
case 5: {*where=new char[sizeof(Float_t)*length]; b.ReadFastArray((Float_t*) *where, length); break;}
case 6: {*where=new char[sizeof(Int_t)*length]; b.ReadFastArray((Int_t*) *where, length); break;}
case 8: {*where=new char[sizeof(Double_t)*length]; b.ReadFastArray((Double_t*)*where, length); break;}
case 11: {*where=new char[sizeof(UChar_t)*length]; b.ReadFastArray((UChar_t*) *where, length); break;}
case 12: {*where=new char[sizeof(UShort_t)*length]; b.ReadFastArray((UShort_t*)*where, length); break;}
case 13: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
case 14: {*where=new char[sizeof(ULong_t)*length]; b.ReadFastArray((ULong_t*) *where, length); break;}
case 15: {*where=new char[sizeof(UInt_t)*length]; b.ReadFastArray((UInt_t*) *where, length); break;}
case 16: {*where=new char[sizeof(Long64_t)*length]; b.ReadFastArray((Long64_t*) *where, length); break;}
case 17: {*where=new char[sizeof(ULong64_t)*length]; b.ReadFastArray((ULong64_t*)*where, length); break;}
case 18: {*where=new char[sizeof(Bool_t)*length]; b.ReadFastArray((Bool_t*) *where, length); break;}
}
}
return;
}
if (atype > 20) {
atype -= 20;
TLeafElement *leaf = (TLeafElement*)fLeaves.UncheckedAt(0);
n *= leaf->GetLenStatic();
}
switch (atype) {
case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
case 16: {b.ReadFastArray((Long64_t*)fAddress, n); break;}
case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
case 18: {b.ReadFastArray((Bool_t*) fAddress, n); break;}
case 9: {Double_t *xx = (Double_t*)fAddress;
Float_t afloat;
for (Int_t ii=0;ii<n;ii++) {
b >> afloat; xx[ii] = Double_t(afloat);
} break;}
}
return;
} else if (fType <= 2) { // branch in split mode
if (fStreamerType > 40 && fStreamerType < 55) {
Int_t atype = fStreamerType - 40;
Int_t n = (Int_t)fBranchCount->GetValue(0,0);
fNdata = n;
Char_t isArray;
b >> isArray;
switch (atype) {
case 1: {b.ReadFastArray((Char_t*) fAddress, n); break;}
case 2: {b.ReadFastArray((Short_t*) fAddress, n); break;}
case 3: {b.ReadFastArray((Int_t*) fAddress, n); break;}
case 4: {b.ReadFastArray((Long_t*) fAddress, n); break;}
case 5: {b.ReadFastArray((Float_t*) fAddress, n); break;}
case 6: {b.ReadFastArray((Int_t*) fAddress, n); break;}
case 8: {b.ReadFastArray((Double_t*)fAddress, n); break;}
case 11: {b.ReadFastArray((UChar_t*) fAddress, n); break;}
case 12: {b.ReadFastArray((UShort_t*)fAddress, n); break;}
case 13: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
case 14: {b.ReadFastArray((ULong_t*) fAddress, n); break;}
case 15: {b.ReadFastArray((UInt_t*) fAddress, n); break;}
case 16: {b.ReadFastArray((Long64_t*) fAddress, n); break;}
case 17: {b.ReadFastArray((ULong64_t*)fAddress, n); break;}
case 18: {b.ReadFastArray((Bool_t*) fAddress, n); break;}
case 9: {Double_t *xx = (Double_t*)fAddress;
Float_t afloat;
for (Int_t ii=0;ii<n;ii++) {
b>> afloat; xx[ii] = Double_t(afloat);
} break;}
}
} else {
fNdata = 1;
if (fAddress) {
//char **arr = &fObject;
fInfo->ReadBuffer(b,(char**)&fObject,fID);
} else {
fNdata = 0;
}
}
return;
}
}
if (fType <=2 && TestBit(kBranchObject)) {
b.MapObject((TObject*)fObject);
}
if (fType == 4) { // STL vector/list of objects
//Error("ReadLeaves","STL split mode not yet implemented (error 1)\n");
Int_t n;
b >> n;
if (n<0 || n>fMaximum) {
if (IsMissingCollection()) {
n = 0;
b.SetBufferOffset( b.Length() - sizeof(n) );
} else {
Error("ReadLeaves",
"Incorrect size read for the container in %s\n\tThe size read is %d while the maximum is %d\n\tThe size is reset to 0 for this entry (%d)",
GetName(),n,fMaximum,GetReadEntry());
n = 0;
}
}
fNdata = n;
if (!fObject) return;
if ( fType == 4) {
// Note: Proxy-helper needs to "embrace" the entire
// streaming of this STL container if the container
// is a set/multiset/map/multimap (what we do not
// know here).
// For vector/list/deque Allocate == Resize
// and Commit == noop.
// TODO: Exception safety a la TPushPop
TVirtualCollectionProxy* proxy = GetCollectionProxy();
TVirtualCollectionProxy::TPushPop helper(proxy,fObject);
void* env = proxy->Allocate(fNdata,true);
Int_t i, nbranches = fBranches.GetEntriesFast();
switch(fSTLtype) {
case TClassEdit::kSet:
case TClassEdit::kMultiSet:
case TClassEdit::kMap:
case TClassEdit::kMultiMap:
for (i=0;i<nbranches;i++) {
TBranch *branch = (TBranch*)fBranches[i];
Int_t nb = branch->GetEntry(GetReadEntry(), 1);
if (nb < 0) break;
}
break;
default:
break;
}
proxy->Commit(env);
}
} else if (fType == 41) { // sub branch of an STL class
//Error("ReadLeaves","STL split mode not yet implemented (error 2)\n");
//char **ppointer = (char**)fAddress;
fNdata = fBranchCount->GetNdata();
if (!fObject) return;
TVirtualCollectionProxy::TPushPop helper(GetCollectionProxy(),fObject);
fInfo->ReadBufferSTL(b,fCollProxy,fNdata,fID,fOffset);
} else if (fType == 3) { //top level branch of a TClonesArray
Int_t n;
b >> n;
if (n<0 || n>fMaximum) {
if (IsMissingCollection()) {
n = 0;
b.SetBufferOffset( b.Length() - sizeof(n) );
} else {
Error("ReadLeaves",
"Incorrect size read for the container in %s\n\tThe size read is %d while the maximum is %d\n\tThe size is reset to 0 for this entry (%d)",
GetName(),n,fMaximum,GetReadEntry());
n = 0;
}
}
fNdata = n;
TClonesArray *clones = (TClonesArray*)fObject;
if (!clones) return;
if (clones->IsZombie()) return;
clones->Clear();
clones->ExpandCreateFast(fNdata);
} else if (fType == 31) { // sub branch of a TClonesArray
fNdata = fBranchCount->GetNdata();
TClonesArray *clones = (TClonesArray*)fObject;
if (!clones) return;
if (clones->IsZombie()) return;
fInfo->ReadBufferClones(b,clones,fNdata,fID,fOffset);
} else if (fType <= 2) { // branch in split mode
if (fBranchCount) fNdata = (Int_t)fBranchCount->GetValue(0,0);
else fNdata = 1;
if (!fInfo) return;
//char **arr = &fObject;
fInfo->ReadBuffer(b,(char**)&fObject,fID);
if (fStreamerType == 6) fNdata = (Int_t)GetValue(0,0);
}
}
//______________________________________________________________________________
void TBranchElement::Reset(Option_t *option)
{
//*-*-*-*-*-*-*-*Reset a Branch*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ====================
//
// Existing buffers are deleted
// Entries, max and min are reset
//
TBranch::Reset(option);
fInfo = fBranchClass->GetStreamerInfo(fClassVersion);
Int_t nbranches = fBranches.GetEntriesFast();
for (Int_t i=0;i<nbranches;i++) {
TBranch *branch = (TBranch*)fBranches[i];
branch->Reset(option);
}
}
//______________________________________________________________________________
void TBranchElement::ResetAddress()
{
//*-*-*-*-*-*-*-*Reset the address of the branch*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ===============================
//
fObject = 0;
TBranch::ResetAddress();
}
//______________________________________________________________________________
namespace {
void SwitchContainer(TObjArray *branches) {
const Int_t nbranches = branches->GetEntriesFast();
for(Int_t i = 0; i < nbranches; ++i) {
TBranchElement *br = (TBranchElement*)branches->At(i);
switch ( br->GetType() ) {
case 31: br->SetType(41); break;
case 41: br->SetType(31); break;
};
SwitchContainer( br->GetListOfBranches());
}
}
}
//______________________________________________________________________________
TClass* TBranchElement::GetParentClass()
{
// Return a pointer to the current type of the data member corresponding to branch element
if ( fParentName.Data()[0] == 0 ) return 0;
return fParentClass;
}
//______________________________________________________________________________
TClass* TBranchElement::GetCurrentClass()
{
// Return a pointer to the current type of the data member corresponding to branch element
TClass* cl = fCurrentClass;
if ( cl ) return cl;
// Get the current type of this data member!
TStreamerInfo *brInfo = GetInfo();
if (brInfo==0) {
cl = gROOT->GetClass(GetClassName());
Assert(cl && cl->GetCollectionProxy());
fCurrentClass = cl;
return cl;
}
TClass *motherCl = brInfo->GetClass();
if (motherCl->GetCollectionProxy()) {
cl = motherCl->GetCollectionProxy()->GetCollectionClass();
if ( cl ) fCurrentClass = cl;
return cl;
}
TStreamerElement *currentStreamerElement =
((TStreamerElement*)brInfo->GetElems()[GetID()]);
TDataMember *dm =
(TDataMember*)motherCl->GetListOfDataMembers()->FindObject(currentStreamerElement->GetName());
TString newType;
if ( dm==0 ) {
// Either the class is not loaded or the data member is gone
if (! motherCl->IsLoaded() ) {
TStreamerInfo *newInfo = motherCl->GetStreamerInfo();
if (newInfo != brInfo) {
TStreamerElement *newElems = (TStreamerElement*)
newInfo->GetElements()->FindObject(currentStreamerElement->GetName());
newType = newElems->GetClassPointer()->GetName();
}
}
} else {
newType = dm->GetTypeName();
}
cl = gROOT->GetClass(newType);
if ( cl ) fCurrentClass = cl;
return cl;
}
namespace {
void CleanParentName(TString& parentName, const char* prefix) {
if (parentName.Index(prefix)==0) {
parentName.Remove(0,strlen(prefix));
}
}
}
//______________________________________________________________________________
Int_t TBranchElement::GetDataMemberOffsetEx(TClass* par_cl, TString& parentName, Int_t off)
{
// remove the current data member name
Ssiz_t pos = parentName.Last('.');
if (pos>0) {
// We had a branch name of the style:
// [X.]Y.Z
// and we are looking up 'Y'
parentName.Remove(pos);
return GetDataMemberOffset(par_cl,parentName);
} else {
// We had a branch name of the style:
// [X.]Z
// and we are looking up 'Z'
// Because we are missing 'Y' (or more exactly the name of the
// thing that contains Z, we can only get the offset of Z and
// then remove the offset Z inside 'Y' (i.e. lOffset)
if (pos==0&&parentName[0]=='.') parentName.Remove(0,1);
return GetDataMemberOffset(par_cl,parentName) - off;
}
}
//______________________________________________________________________________
void TBranchElement::InitializeOffsets()
{
Int_t nbranches = fBranches.GetEntriesFast();
TClass *clparent = GetParentClass();
TClass *clm = fBranchClass;
if (fType == 31 || fType == 41) {
if ( fClassName != fParentName ) {
// We are in the case where we have a missing link.
// This information is realliable here (or so it seems)
// (In other cases fParentName does not seems to be set correctly in all cases).
if (clparent != clm) {
if (!clparent || !clm) {
fInitOffsets = kTRUE;
return;
}
const char *ename = fID<0 ? 0 : ((TStreamerElement*)fInfo->GetElems()[fID])->GetName();
Int_t lOffset = clm->GetStreamerInfo()->GetOffset(ename); // offset in the local streamerInfo.
TBranchElement *parent = (TBranchElement*) GetMother()->GetSubBranch(this);
TString parentDataName( GetName() );
// remove the TClonesArray main name (if present)
CleanParentName(parentDataName,fBranchCount->GetName());
// remove the parent branch name (if present)
CleanParentName(parentDataName,parent->GetName());
fOffset = GetDataMemberOffsetEx(clparent, parentDataName, lOffset);
}
}
if (gDebug > 0 ) {
printf("fOffset=%d\n",fOffset);
}
}
else if (nbranches == 0) {
if (clparent && clparent != clm) {
// We need to discover if 'this' represents a direct datamember of the class in parent or
// if it is an indirect one (with a missing branch in the hierachy)
TBranchElement *parent = (TBranchElement*) GetMother()->GetSubBranch(this);
assert(parent!=this);
Int_t parentID = parent->GetID();
assert(parentID>=0); // if the ID was negative, the branch would not have been split!
TStreamerInfo *parentInfo = parent->GetInfo();
assert(parentInfo != 0);
TStreamerElement *parentElem = (TStreamerElement*)parentInfo->GetElems()[parentID];
TClass *parentBranchClass = parentElem->GetClassPointer();
if ( ! parentBranchClass->InheritsFrom(clm) ) {
// We are in the case where there is a missing branch in the hiearchy
TString parentDataName( GetName() );
const char *ename = fID<0 ? 0 : ((TStreamerElement*)fInfo->GetElems()[fID])->GetName();
Int_t lOffset = clm->GetStreamerInfo()->GetOffset(ename); // offset in the local streamerInfo.
// remove the parent branch name (if present)
CleanParentName(parentDataName,parent->GetName());
fParentOffset = GetDataMemberOffsetEx(parentBranchClass, parentDataName, lOffset);
if (parent->fType==1) {
const char *name = GetName();
const char *pos = strchr( name, '.');
if (pos && fParentOffset) {
size_t idx = (pos-name);
TClass *pbc = parentBranchClass;
if ( pbc && (parentInfo=pbc->GetStreamerInfo()) ) {
std::string enam( name, idx );
TObject *info = parentInfo->GetElements()->FindObject(enam.c_str());
if (info) {
// If all the condition above are fullfilled we have already
// compensated for the missing branch.
fParentOffset=0;
}
}
}
}
} else {
// Case where we have a proper branch hierachy
// fObject is already correct!
// nothing to do :)
// fprintf(stderr,"section has nothing to do!\n");
}
}
}
if ( nbranches > 0 ) {
Int_t parentID = 0;
TClass* parentBranchClass = 0;
TStreamerElement* elem = fID<0 ? 0 : ((TStreamerElement*)fInfo->GetElems()[fID]);
const char *ename = elem ? elem->GetName() : 0;
fBranchOffset = new Int_t[nbranches];
fBranchTypes = new Bool_t[nbranches];
//for (Int_t j=0; j<nbranches; j++ ) {
// fBranchOffset[j] = 0;
// TBranch *abranch = (TBranch*)fBranches[j];
// fBranchTypes[j] = abranch->InheritsFrom(TBranchElement::Class());
//}
for (Int_t i=0; i<nbranches;i++ ) {
fBranchOffset[i] = 0;
TBranch *abranch = (TBranch*)fBranches[i];
fBranchTypes[i] = abranch->InheritsFrom(TBranchElement::Class());
//just in case a TBranch had been added to a TBranchElement!
if ( !fBranchTypes[i] ) {
continue;
}
TBranchElement *branch = (TBranchElement*)abranch;
Int_t nb2 = branch->GetListOfBranches()->GetEntriesFast();
Int_t lOffset = 0; // offset in the local streamerInfo.
lOffset = clm->GetStreamerInfo()->GetOffset(ename);
Int_t id = branch->GetID();
if (!clparent) clparent = clm;
// Test if we are in the case where the class described by 'clparent'
// did not get its own branch in the tree. In this case the immediate
// parent branch will have a different type.
// First get the immediate parent (i.e a branch which has 'branch' has
// a direct sub-branch.
TStreamerInfo *info = branch->GetInfo();
TBranchElement *parent = this; // = (TBranchElement*) branch->GetMother()->GetSubBranch(branch);
//assert(parent==this);
parentID = parent->GetID();
assert(parentID>=0 || parentID==-2 || parentID==-1);
// if the ID was negative, the branch would not have been split!
// -2 = Base class; -1 = (STL-)Collection
TStreamerInfo *parentInfo = fInfo; // since parent==this parent->GetInfo();
assert(parentInfo != 0);
switch(parentID) {
case -2:
case -1:
parentBranchClass = parentInfo->GetClass();
break;
default: {
TStreamerElement *parentElem = (TStreamerElement*)parentInfo->GetElems()[parentID];
parentBranchClass = parentElem->GetClassPointer();
break;
}
}
if ( nb2 > 0 ) {
// The branch has some sub-branches
if (info) {
Int_t *leafOffsets = info->GetOffsets();
TClass *containingClass = info->GetClass();
if ( ! parentBranchClass->InheritsFrom(containingClass) ) {
// We are in the case where there is a missing branch in the hiearchy
// Since we do not have a proper hierachy, fObject does NOT point
// to object of type 'clparent'. Instead it points to an object
// which 'contains' an object of type 'clparent'. So the first
// order of business is to find the address of the object of type
// 'clparent' and then just add 'leafOffsets[id]' (i.e. the offset
// of this branch inside the object of type 'clparent'
// We need to extract from branch->GetName() the qualified name
// of the data member which contains us
TString parentDataName = branch->GetName();
// remove the main branch name (if present)
CleanParentName(parentDataName,branch->GetMother()->GetName());
if (leafOffsets) {
Int_t offset = GetDataMemberOffsetEx(parentBranchClass, parentDataName, lOffset);
fBranchOffset[i] = offset + leafOffsets[id];
} else {
Error("SetAddress","info=%s, leafOffsets=0",info->GetName());
}
} else {
// Case where we have a proper branch hierachy fObject is already correct!
if (leafOffsets) {
fBranchOffset[i] = leafOffsets[id];
} else {
Error("SetAddress","info=%s, leafOffsets=0",info->GetName());
}
}
} else {
// fInfo==0
Error("SetAddress","branch=%s, info=0",branch->GetName());
}
}
else if ( fType == 1 ) {
// Offset seems to need correction for TStreamerBases
const char *name = branch->GetName();
const char *pos = strchr( name, '.');
if (pos) {
size_t idx = (pos-name);
// Broken branch hierarchy: need to look for offset
// in the parents StreamerInfo if the branch represents
// a TStreamerBase
TClass *pbc = parentBranchClass;
if ( pbc && (parentInfo=pbc->GetStreamerInfo()) ) {
std::string enam( branch->GetName(), idx );
fBranchOffset[i] = parentInfo->GetOffset(enam.c_str());
}
else {
Error("SetAddress","branch=%s, parentInfo==0",branch->GetName());
}
}
}
}
}
fInitOffsets = kTRUE;
}
//______________________________________________________________________________
void TBranchElement::SetAddress(void *add)
{
//*-*-*-*-*-*-*-*Set address of this branch*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ====================
//
if (TestBit(kDoNotProcess)) return;
if (fType < 0) return;
//special case when called from code generated by TTree::MakeClass
if (Long_t(add) == -1) {
SetBit(kWarn);
fAddress = (char*)add;
return;
}
fReadEntry = -1;
//build the StreamerInfo if first time for the class
TClass *cl = fBranchClass;
if ( !fInfo ) GetInfo();
Int_t nbranches = fBranches.GetEntriesFast();
if (gDebug > 0) {
printf("SetAddress, branch:%s, classname=%s, parent=%s, fID=%d, fType=%d, nbranches=%d, add=%p, fInfo=%s, version=%d => ",
GetName(),fClassName.Data(),fParentName.Data(),fID,fType,nbranches,add,fInfo->GetName(),fClassVersion);
}
fAddress = (char*)add;
if (fTree->GetMakeClass()) {
if (fID >= 0) {
if (!fInfo) {fObject=fAddress; return;}
fObject = fAddress - fInfo->GetOffsets()[fID];
return;
}
}
if (fID < 0) {
if (fAddress) {
char **ppointer = (char**)fAddress;
fObject = *ppointer;
if (!fObject && cl) {
//Remember if we build an object of an emulated class
if (!cl->GetClassInfo()) SetBit(kDeleteObject);
fObject = (char*)cl->New();
*ppointer = fObject;
}
} else {
//Remember if we build an object of a emulated class
if (!cl->GetClassInfo()) SetBit(kDeleteObject);
fObject = (char*)cl->New();
}
if (!fAddress) fAddress = (char*)&fObject;
} else {
fObject = fAddress;
}
// Check whether the container type is still the same
if (fType ==3) {
TClass *clm = gROOT->GetClass(fClonesName.Data());
if (clm) {
clm->BuildRealData(); //just in case clm derives from an abstract class
clm->GetStreamerInfo();
}
TClass *newType = GetCurrentClass();
if ( newType && newType != TClonesArray::Class() ) {
// The data type of the container was changed
// Let's check if it is a compatible type:
Bool_t matched = kFALSE;
if (newType->GetCollectionProxy()) {
TClass *content = newType->GetCollectionProxy()->GetValueClass();
if (clm==content) {
matched = kTRUE;
} else {
Warning("SetAddress",
"The type of %s was changed from TClonesArray to %s but the content do not match (was %s)!",
GetName(),newType->GetName(),fClonesName.Data());
}
} else {
Warning("SetAddress",
"The type of the %s was changed from TClonesArray to %s but we do not have a TVirtualCollectionProxy for that container type!",
GetName(),newType->GetName());
}
if (matched) {
// Change from 3/31 to 4/41
SetType(4);
SwitchContainer(GetListOfBranches());
// Set the proxy.
fSTLtype = TMath::Abs(TClassEdit::IsSTLCont(newType->GetName()));
fCollProxy = newType->GetCollectionProxy()->Generate();
} else {
fAddress = 0;
}
}
}
//Special case for an STL container.
if (fType==4) {
TClass *newType = GetCurrentClass();
if ( newType && newType != GetCollectionProxy()->GetCollectionClass() ) {
// Let's check if it is a compatible type:
TVirtualCollectionProxy *newProxy = newType->GetCollectionProxy();
TVirtualCollectionProxy *oldProxy = GetCollectionProxy();
if (newProxy && oldProxy->GetValueClass() == newProxy->GetValueClass()
&& ( (oldProxy->GetValueClass() ==0 &&
oldProxy->GetType() == newProxy->GetType()) ||
(oldProxy->GetValueClass() &&
oldProxy->HasPointers() == newProxy->HasPointers()) ) ) {
if ( fSTLtype==TClassEdit::kNotSTL ) {
fSTLtype = TMath::Abs(TClassEdit::IsSTLCont(newType->GetName()));
}
fCollProxy = newType->GetCollectionProxy()->Generate();
} else {
// The new collection and the old collection are not compatible,
// we can not use the new collection to read the data.
// Actually if could check whether the new collection is a
// compatible ROOT collection.
if ( newType == TClonesArray::Class() &&
( oldProxy->GetValueClass() && !oldProxy->HasPointers()
&& oldProxy->GetValueClass()->InheritsFrom(TObject::Class()))) {
// We can not insure that the TClonesArray is set for the
// proper class ( oldProxy->GetValueClass() ), so we assume that
// the transformation was done properly by the class designer.
// Change from 4/41 to 3/31
SetType(3);
SwitchContainer(GetListOfBranches());
// Reset the proxy.
fSTLtype = kNone;
switch(fStreamerType) {
case TStreamerInfo::kAny:
case TStreamerInfo::kSTL:
fStreamerType = TStreamerInfo::kObject;
break;
case TStreamerInfo::kAnyp:
case TStreamerInfo::kSTLp:
fStreamerType = TStreamerInfo::kObjectp;
break;
case TStreamerInfo::kAnyP:
fStreamerType = TStreamerInfo::kObjectP;
break;
}
fClonesName = oldProxy->GetValueClass()->GetName();
delete fCollProxy; fCollProxy = 0;
TClass *clm = gROOT->GetClass(fClonesName);
if (clm) {
clm->BuildRealData(); //just in case clm derives from an abstract class
clm->GetStreamerInfo();
}
} else {
fAddress = 0;
}
}
}
}
//special case for a TClonesArray when address is not yet set
//we must create the clonesarray first
if (fType==3) {
if (fAddress) {
if (fStreamerType==61) {
// Case of an embedded ClonesArray
fObject = fAddress;
// Check if it has already been properly build.
TClonesArray *clones = (TClonesArray*)fObject;
if (clones->GetClass()==0) {
new (fObject) TClonesArray(fClonesName.Data());
}
} else {
TClonesArray **ppointer = (TClonesArray**)fAddress;
if (!*ppointer) *ppointer = new TClonesArray(fClonesName.Data());
fObject = (char*)*ppointer;
}
if (!fObject) fAddress = 0;
}
if (!fAddress) {
//SetBit(kDeleteObject);
fObject = (char*)new TClonesArray(fClonesName.Data());
fAddress = (char*)&fObject;
}
} else if (fType==4) {
TVirtualCollectionProxy* proxy = GetCollectionProxy(); // initialize fCollProxy
if (fAddress) {
if (fStreamerType==61 ||
fStreamerType==TStreamerInfo::kAny ||
fStreamerType==TStreamerInfo::kSTL) {
// Case of an embedded container?
fObject = fAddress;
} else {
void **ppointer = (void**)fAddress;
if (!*ppointer) *ppointer = proxy->New();
fObject = (char*)*ppointer;
}
if (!fObject) fAddress = 0;
}
if (!fAddress) {
//SetBit(kDeleteObject);
fObject = (char*)proxy->New();
fAddress = (char*)&fObject;
}
} else if (fType==41) {
GetCollectionProxy(); // initialize fCollProxy
}
if (gDebug > 0 ) {
printf("fAddress=%p, fObject=%p, \n",fAddress,fObject);
}
if ( !fInfo ) return;
if ( !fInitOffsets ) InitializeOffsets();
if (fType == 31 || fType == 41) {
return;
}
if (nbranches == 0) {
fObject += fParentOffset;
return;
}
for (Int_t i=0;i<nbranches;i++) {
TBranch *abranch = (TBranch*)fBranches[i];
abranch->SetAddress(fObject + fBranchOffset[i]);
}
}
//______________________________________________________________________________
void TBranchElement::SetAutoDelete(Bool_t autodel)
{
//*-*-*-*-*-*-*-*Set the AutoDelete bit
//*-* ====================
// This function can be used to instruct Root in TBranchElement::ReadBasket
// to not delete the object referenced by a branchelement before reading a
// new entry. By default, the object is deleted.
// If autodel is kTRUE, this existing object will be deleted, a new object
// created by the default constructor, then object->Streamer called.
// If autodel is kFALSE, the existing object is not deleted. Root assumes
// that the user is taking care of deleting any internal object or array
// This can be done in Streamer itself.
// If this branch has sub-branches, the function sets autodel for these
// branches as well.
// We STRONGLY suggest to activate this option by default when you create
// the top level branch. This will make the read phase more efficient
// because it minimizes the numbers of new/delete operations.
// Once this option has been set and the Tree is written to a file, it is
// not necessary to specify the option again when reading, unless you
// want to set the opposite mode.
//
TBranch::SetAutoDelete(autodel);
}
//______________________________________________________________________________
void TBranchElement::SetBasketSize(Int_t buffsize)
{
// Reset basket size for all subbranches of this branchelement
TBranch::SetBasketSize(buffsize);
Int_t nbranches = fBranches.GetEntriesFast();
for (Int_t i=0;i<nbranches;i++) {
TBranch *branch = (TBranch*)fBranches[i];
branch->SetBasketSize(fBasketSize);
}
}
//______________________________________________________________________________
void TBranchElement::SetBranchCount(TBranchElement *bre)
{
// Set the branch count for this branch
fBranchCount = bre;
TLeafElement *lfc = (TLeafElement *)bre->GetListOfLeaves()->At(0);
TLeafElement *leaf = (TLeafElement *)GetListOfLeaves()->At(0);
if (lfc && leaf) leaf->SetLeafCount(lfc);
}
//______________________________________________________________________________
void TBranchElement::Streamer(TBuffer &R__b)
{
// Stream an object of class TBranchElement.
if (R__b.IsReading()) {
TBranchElement::Class()->ReadBuffer(R__b, this);
fParentClass.SetName(fParentName);
fBranchClass.SetName(fClassName);
} else {
TDirectory *dirsav = fDirectory;
fDirectory = 0; // to avoid recursive calls
TBranchElement::Class()->WriteBuffer(R__b, this);
// make sure that all TStreamerInfo objects referenced by
// this class are written to the file
if (fInfo) fInfo->ForceWriteInfo((TFile *)R__b.GetParent(), kTRUE);
// if branch is in a separate file save this branch
// as an independent key
if (!dirsav) return;
if (!dirsav->IsWritable()) {fDirectory = dirsav; return;}
TDirectory *pdirectory = fTree->GetDirectory();
if (!pdirectory) {fDirectory = dirsav; return;}
const char *treeFileName = pdirectory->GetFile()->GetName();
TBranch *mother = GetMother();
const char *motherFileName = treeFileName;
if (mother && mother != this) {
motherFileName = mother->GetFileName();
}
if (fFileName.Length() > 0 && strcmp(motherFileName,fFileName.Data())) {
TDirectory *cursav = gDirectory;
dirsav->cd();
Write();
cursav->cd();
}
fDirectory = dirsav;
}
}
//______________________________________________________________________________
Int_t TBranchElement::Unroll(const char *name, TClass *cltop, TClass *cl,Int_t basketsize, Int_t splitlevel, Int_t btype)
{
// unroll base classes and loop on all elements of class cl
if (cl == TObject::Class() && cltop->CanIgnoreTObjectStreamer()) return 0;
Bool_t optim = TStreamerInfo::CanOptimize();
if (splitlevel > 0) TStreamerInfo::Optimize(kFALSE);
TStreamerInfo *info = fTree->BuildStreamerInfo(cl);
TStreamerInfo::Optimize(optim);
if (!info) return 0;
TClass *clbase;
Int_t ndata = info->GetNdata();
ULong_t *elems = info->GetElems();
TStreamerElement *elem;
TBranchElement *branch;
char branchname[kMaxLen];
Int_t jd = 0;
Int_t unroll = 0;
if (ndata==1 && cl->GetCollectionProxy() &&
strcmp(((TStreamerElement*)elems[0])->GetName(),"This")==0) {
// This streamerInfo only refers to the collection itself
return 1;
}
for (Int_t i=0;i<ndata;i++) {
elem = (TStreamerElement*)elems[i];
Int_t offset = elem->GetOffset();
char *oldPointer = fBranchPointer;
if (gDebug > 0) printf("Unroll name=%s, cltop=%s, cl=%s, i=%d, elem=%s, offset=%d, splitlevel=%d, fBranchPointer=%lx, btype=%d \n",name,cltop->GetName(),cl->GetName(),i,elem->GetName(),elem->GetOffset(),splitlevel,(Long_t)fBranchPointer,btype);
if (elem->IsA() == TStreamerBase::Class()) {
clbase = gROOT->GetClass(elem->GetName());
if (clbase->Property() & kIsAbstract) {
if (cl->InheritsFrom("TCollection")) unroll = -1;
}
if (unroll < 0 && (btype != 31 || btype != 41)) return -1;
if (gDebug > 0) printf("Unrolling base class, cltop=%s, clbase=%s\n",cltop->GetName(),clbase->GetName());
if (btype==31 || btype==41) {
fBranchPointer += offset;
unroll = Unroll(name,cltop,clbase,basketsize,splitlevel-1,btype);
fBranchPointer = oldPointer;
if (unroll < 0) {
if (strlen(name)) sprintf(branchname,"%s.%s",name,elem->GetFullName());
else sprintf(branchname,"%s",elem->GetFullName());
branch = new TBranchElement(branchname,info,jd,0,basketsize,0,btype);
branch->SetParentClass(cltop);
fBranches.Add(branch);
}
} else if (clbase->GetListOfRealData()->GetSize()!=0) {
// We do not create a branch for an empty base class:
char *pointer = fBranchPointer + offset;
if (strlen(name)) {
sprintf(branchname,"%s.%s",name,elem->GetFullName());
// First claim that we have the short name (to fool the children)
branch = new TBranchElement(name,info,jd,pointer,basketsize,splitlevel,btype);
// Then reset it to the proper name
branch->SetName(branchname);
branch->SetTitle(branchname);
} else {
sprintf(branchname,"%s",elem->GetFullName());
branch = new TBranchElement(branchname,info,jd,pointer,basketsize,splitlevel,btype);
}
// branch = new TBranchElement(branchname,info,jd,pointer,basketsize,splitlevel-1,btype);
branch->SetParentClass(cltop);
fBranches.Add(branch);
if (0 && unroll < 0) {
branch = new TBranchElement(branchname,info,jd,0,basketsize,0,btype);
branch->SetParentClass(cltop);
fBranches.Add(branch);
}
}
} else {
if (strlen(name)) sprintf(branchname,"%s.%s",name,elem->GetFullName());
else sprintf(branchname,"%s",elem->GetFullName());
if ( splitlevel > 1 &&
( elem->IsA() == TStreamerObject::Class() || elem->IsA() == TStreamerObjectAny::Class() ) ) {
clbase = gROOT->GetClass(elem->GetTypeName());
if (clbase->Property() & kIsAbstract) return -1;
if (gDebug > 0) printf("Unrolling object class, cltop=%s, clbase=%s\n",cltop->GetName(),clbase->GetName());
fBranchPointer += offset;
if (elem->CannotSplit()) {
unroll = -1;
} else if (clbase->InheritsFrom(TClonesArray::Class())) {
branch = new TBranchElement(branchname,info,jd,fBranchPointer ,basketsize,splitlevel-1,btype);
branch->SetParentClass(cltop);
fBranches.Add(branch);
unroll = 0;
} else {
unroll = Unroll(branchname,cltop,clbase,basketsize,splitlevel-1,btype);
}
fBranchPointer = oldPointer;
if (unroll < 0) {
char *pointer = fBranchPointer + offset;
branch = new TBranchElement(branchname,info,jd,pointer,basketsize,0,btype);
branch->SetParentClass(cltop);
fBranches.Add(branch);
}
} else if (elem->IsA() == TStreamerSTL::Class() && !elem->IsaPointer()) {
// here all STL classes are handled
Int_t subSplitlevel = splitlevel-1;
if (btype == 31 || btype == 41 || elem->CannotSplit()) {
subSplitlevel = 0;
}
char* pointer = fBranchPointer + offset;
branch = new TBranchElement(branchname,info,jd,/* 0 */ pointer ,basketsize,subSplitlevel,btype);
branch->SetParentClass(cltop);
fBranches.Add(branch);
} else {
//fBranchPointer may be null in case of a TClonesArray inside another TClonesArray
if ((btype != 31 && btype != 41) && fBranchPointer &&
( elem->GetClassPointer() == TClonesArray::Class()
|| (elem->IsA() == TStreamerSTL::Class() && !elem->CannotSplit())
)
) {
//process case of a TClonesArray in a derived class
char *pointer = fBranchPointer + offset;
branch = new TBranchElement(branchname,info,jd,pointer,basketsize,splitlevel-1,btype);
} else {
branch = new TBranchElement(branchname,info,jd,0,basketsize,0,btype);
branch->SetType(btype);
}
branch->SetParentClass(cltop);
fBranches.Add(branch);
}
}
jd++;
}
return 1;
}
//______________________________________________________________________________
TVirtualCollectionProxy *TBranchElement::GetCollectionProxy()
{
if (fCollProxy) return fCollProxy;
TBranchElement *thiscast = const_cast<TBranchElement*>(this);
if (fType==4 ) {
const char *ty;
if (fID>=0) ty = ((TStreamerElement*)thiscast->GetInfo()->GetElems()[fID])->GetTypeName();
else ty = fClassName.Data();
TClass *cl = gROOT->GetClass(ty);
fCollProxy = cl->GetCollectionProxy()->Generate();
fSTLtype = TClassEdit::IsSTLCont(ty);
if ( fSTLtype<0 ) fSTLtype = -fSTLtype;
} else if(fType==41) {
thiscast->fCollProxy = fBranchCount->fCollProxy;
}
return fCollProxy;
}
ROOT page - Class index - Class Hierarchy - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.