// @(#)root/tree:$Name:  $:$Id: TBranchElement.cxx,v 1.76 2002/01/13 07:43:03 brun Exp $
// Author: Rene Brun   14/01/2001

/*************************************************************************
 * Copyright (C) 1995-2000, 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 "TClonesArray.h"
#include "TTree.h"
#include "TBasket.h"
#include "TLeafElement.h"
#include "TVirtualPad.h"
#include "TClass.h"
#include "TRealData.h"
#include "TDataType.h"
#include "TDataMember.h"
#include "TStreamerInfo.h"
#include "TStreamerElement.h"
#include "TBrowser.h"
#include "TFolder.h"

const Int_t kMaxLen = 1024;
R__EXTERN  TTree *gTree;

ClassImp(TBranchElement)

//______________________________________________________________________________
 TBranchElement::TBranchElement(): TBranch()
{
//*-*-*-*-*-*Default constructor for BranchElement*-*-*-*-*-*-*-*-*-*
//*-*        ====================================

   fNleaves = 1;
   fInfo = 0;
   fBranchCount = 0;
   fBranchCount2 = 0;
   fObject = 0;
   fMaximum = 0;
   fBranchPointer = 0;
   fNdata = 1;
}


//______________________________________________________________________________
 TBranchElement::TBranchElement(const char *bname, TStreamerInfo *sinfo, Int_t id, char *pointer, Int_t basketsize, Int_t splitlevel, Int_t btype)
    :TBranch()
{
// Create a BranchElement
//
// If splitlevel > 0 this branch in turn is split into sub branches

   if (gDebug > 0) {
      printf("BranchElement, bname=%s, sinfo=%s, id=%d, splitlevel=%dn",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;
   fID           = id;
   fStreamerType = -1;
   fType         = 0;
   fBranchCount  = 0;
   fBranchCount2 = 0;
   fObject       = 0;
   fBranchPointer= 0;
   fNdata        = 1;
   fClassVersion = cl->GetClassVersion();
   fTree         = gTree;
   fMaximum      = 0;
   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=%dn",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) basketsize = 100;
   fBasketSize     = basketsize;
   fBasketEntry    = new Int_t[fMaxBaskets];
   fBasketBytes    = new Int_t[fMaxBaskets];
   fBasketSeek     = new Seek_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);

   // 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) {
      TClass *clm;
      if (element->CannotSplit()) {
         //printf("element: %s/%s will not be splitn",element->GetName(),element->GetTitle());
      } 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(element->GetTypeName(),"TClonesArray") || !strcmp(element->GetTypeName(),"TClonesArray*")) {
         Bool_t ispointer = !strcmp(element->GetTypeName(),"TClonesArray*");
         TClonesArray *clones;
         if (ispointer) {
            char **ppointer = (char**)(pointer);
            clones = (TClonesArray*)(*ppointer);
         } else {
            clones = (TClonesArray*)pointer;
         }
         if (!clones) return; // TClonesArray must exist
         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 *basket = new TBasket(name,fTree->GetName(),this);
         fBaskets.Add(basket);
         // ===> 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 (!strchr(element->GetTypeName(),'*') && (fStreamerType == TStreamerInfo::kObject || fStreamerType == TStreamerInfo::kAny)) {
         // ===> create sub branches for members that are classes
         fType = 2;
         clm = gROOT->GetClass(element->GetTypeName());
         if (Unroll(name,clm,clm,basketsize,splitlevel,0) >= 0) return;
      } else if (strstr(element->GetTypeName(),"vector<")) {
         // ===> create sub branches for each data member of a STL vector
         //      if it is a vector of class objects.
         //      STL vectors like vector<float> are not split
         fType = 0;
         char classname[kMaxLen];
         strcpy(classname,element->GetTypeName()+7);
         char *star = strchr(classname,'>');
         *star = 0;
         clm = gROOT->GetClass(classname);
         if (clm) {
            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 the class
            fType = 4;
            char branchname[kMaxLen];
            sprintf(branchname,"%s_",name);
            SetTitle(branchname);
            Unroll(name,clm,clm,basketsize,splitlevel,41);
            TStreamerSTL *stl = (TStreamerSTL*)element;
            if (stl->GetSTLtype() == 1 && stl->GetCtype() == 61) {
               printf("will split this STL vector: %s of %sn",name,classname);
            }
            if (stl->GetSTLtype() == 41 && stl->GetCtype() == 61) {
               printf("will split this pointer to STL vector: %s of %sn",name,classname);
            }
            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()
{
// Create a BranchElement
//
// If splitlevel > 0 this branch in turn is split into sub branches

   char name[kMaxLen];
   strcpy(name,bname);
   fSplitLevel   = splitlevel;
   fInfo         = TClonesArray::Class()->GetStreamerInfo();
   fID           = 0;
   fStreamerType = -1;
   fType         = 0;
   fClassVersion = TClonesArray::Class()->GetClassVersion();
   fBranchCount  = 0;
   fBranchCount2 = 0;
   fObject       = 0;
   fBranchPointer= 0;
   fMaximum      = 0;

   fTree       = gTree;
   fDirectory  = fTree->GetDirectory();
   fFileName   = "";

   SetName(name);
   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;
   fBasketEntry    = new Int_t[fMaxBaskets];
   fBasketBytes    = new Int_t[fMaxBaskets];
   fBasketSeek     = new Seek_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) {
      // ===> 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();
      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;
   }

   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()
{
//*-*-*-*-*-*Default destructor for a BranchElement*-*-*-*-*-*-*-*-*-*-*-*
//*-*        =====================================

   fBranches.Delete();
   
   //SetAddress may have allocated an object. Must delete it
   if (TestBit(kDeleteObject)) {
      if (fObject) {
         //TObject *obj = (TObject*)fObject;
         // objects of fake classes allocated in SetAddress should be deleted
         //printf("deleting fObject=%x of class: %s, branch: %s, fAddress=%xn",obj,fClassName.Data(),GetName(),fAddress);
         //delete obj;
      }
   }
}


//______________________________________________________________________________
 void TBranchElement::Browse(TBrowser *b)
{
   Int_t nbranches = fBranches.GetEntriesFast();
   if (nbranches > 0) {
      fBranches.Browse(b);
   } else {
      // Get the name and strip any extra brackets
      // in order to get the full arrays.
      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)!='.') {
               mothername.Append(".");
            }
            name.Prepend(mothername);
         }
      }

      GetTree()->Draw(name);
      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);
      bre->SetType(31);
      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=%sn",bre->GetName(),bc2->GetName());
      }
   }
}


//______________________________________________________________________________
 Int_t TBranchElement::Fill()
{
//*-*-*-*-*-*-*-*Loop on all leaves of this branch to fill Basket buffer*-*-*
//*-*            =======================================================

   Int_t nbytes = 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 (nbranches) {
      if (fType == 3)  nbytes += TBranch::Fill();  //TClonesArray counter
      else             fEntries++;
      for (Int_t i=0;i<nbranches;i++)  {
         TBranchElement *branch = (TBranchElement*)fBranches[i];
         if (!branch->TestBit(kDoNotProcess)) nbytes += branch->Fill();
      }
   } else {
      if (!TestBit(kDoNotProcess)) nbytes += TBranch::Fill();
   }
   if (fTree->Debug() > 0) {
      Int_t entry = (Int_t)fEntries;
      if (entry >= fTree->GetDebugMin() && entry <= fTree->GetDebugMax()) {
         printf("Fill: %d, branch=%s, nbytes=%dn",entry,GetName(),nbytes);
      }
   }
   return nbytes;
}

//______________________________________________________________________________
 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
     //printf ("STL split mode not yet implementedn");
  } else if (fType == 41) {   // sub branch of an STL class
    //char **ppointer = (char**)fAddress;
  } else if (fType == 3) {   //top level branch of a TClonesArray
    TClonesArray *clones = (TClonesArray*)fObject;
    if (!clones) return;
    Int_t n = clones->GetEntriesFast();
    if (n > fMaximum) fMaximum = n;
    b << n;
  } else if (fType == 31) {   // sub branch of a TClonesArray
    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->WriteBuffer(b,fObject,fID);
    if (fStreamerType == 6) {
       if (n > fMaximum) fMaximum = n;
    }
  }
}

//______________________________________________________________________________
 Int_t TBranchElement::GetEntry(Int_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 or an I/O error occurs, the function returns 0.
//
//  See IMPORTANT REMARKS in TTree::GetEntry

   Int_t nbranches = fBranches.GetEntriesFast();

   Int_t nbytes = 0;

   // if branch address is not yet set, must set all addresses starting
   // with the top level parent branch
   if (fAddress == 0 && fTree->GetMakeClass() == 0) {
      TBranchElement *mother = GetMother();
      TClass *cl = gROOT->GetClass(mother->GetClassName());
      if (fInfo && fInfo->GetOffsets()) fInfo->BuildOld();
      if (!mother || !cl) return 0;
      if (!mother->GetAddress()) mother->SetAddress(0);
   }

   if (nbranches) {
      //branch has daughters
      //one must always read the branch counter. 
      //In the case when one reads consicutively twice the same entry,
      //the user may have cleared the TClonesArray between the 2 GetEntry
      if (fType == 3) nbytes += TBranch::GetEntry(entry, getall);

      for (Int_t i=0;i<nbranches;i++)  {
         TBranch *branch = (TBranch*)fBranches[i];
         nbytes += branch->GetEntry(entry, getall);
      }
   } else {
      //terminal branch
      if (fBranchCount && fBranchCount->GetReadEntry() != entry) nbytes += fBranchCount->TBranch::GetEntry(entry,getall);
      nbytes += TBranch::GetEntry(entry, getall);
   }

   if (fTree->Debug() > 0) {
      if (entry >= fTree->GetDebugMin() && entry <= fTree->GetDebugMax()) {
         printf("GetEntry: %d, branch=%s, nbytes=%dn",entry,GetName(),nbytes);
      }
   }
   return nbytes;
}

//______________________________________________________________________________
 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);
      }
      return fInfo;
   }
   TClass *cl = gROOT->GetClass(fClassName.Data());
   if (cl) {
      TStreamerInfo::Optimize(kFALSE);
      if (cl == TClonesArray::Class()) fClassVersion = TClonesArray::Class()->GetClassVersion();
      fInfo = cl->GetStreamerInfo(fClassVersion);
      if (fInfo && !fInfo->GetOffsets()) {
         fInfo->Compile();
      }
      TStreamerInfo::Optimize(optim);
   }
   return fInfo;
}

//______________________________________________________________________________
 Int_t TBranchElement::GetMaximum() const
{
// Return maximum count value of the branchcount if any

   if (fBranchCount) return fBranchCount->GetMaximum();
   return fMaximum;
}

//______________________________________________________________________________
 TBranchElement *TBranchElement::GetMother() const
{
// Get top level branch parent of this branch
// A top level branch has its fID negative.

   TIter next(fTree->GetListOfBranches());
   TBranch *branch;
   TBranchElement *bre, *br;
   while ((branch=(TBranch*)next())) {
      if (branch->IsA() != TBranchElement::Class()) continue;
      bre = (TBranchElement*)branch;
      br = bre->GetSubBranch(this);
      if (br) return bre;
   }
   return 0;
}

//______________________________________________________________________________
 TBranchElement *TBranchElement::GetSubBranch(const TBranchElement *br) const
{
// recursively find branch br in the list of branches of this branch.
// return null if br is not in this branch hierarchy.

   if (br == this) return (TBranchElement*)this;
   TIter next(((TBranchElement*)this)->GetListOfBranches());
   TBranchElement *branch, *br2;
   while ((branch = (TBranchElement*)next())) {
      br2 = branch->GetSubBranch(br);
      if (br2) return br2;
   }
   return 0;
}

//______________________________________________________________________________
 const char *TBranchElement::GetTypeName() const
{
   // return type name of element in the branch

   if (fType == 3) {
      return "Int_t";
   }
   if (fStreamerType <=0 || fStreamerType >= 60) return fClassName.Data();
   const char *types[16] = {"","Char_t","Short_t","Int_t","Long_t","Float_t",
      "Int_t","","Double_t","","","UChar_t","UShort_t","UInt_t","ULong_t","UInt_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) {    //top level branch of a TClonesArray
       return (Double_t)fNdata;
     } 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);
     } 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 {
      return fInfo->GetValue(fObject,fID,j,-1);
   }
}

//______________________________________________________________________________
 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 == 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 <= 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 {
      //return fInfo->GetValue(fObject,fID,j,-1);
      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;
   else                return kFALSE;
}

//______________________________________________________________________________
 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 len) const
{
// Prints leaf value

  if (fTree->GetMakeClass()) {
     if (!fAddress) return;
     if (fType == 3) {    //top level branch of a TClonesArray
       printf(" %-15s = %dn",GetName(),fNdata);
       return;
     } else if (fType == 31) {    // sub branch of a TClonesArray
       Int_t n = TMath::Min(10,fNdata);
       Int_t atype = fStreamerType+20;
       if (fStreamerType > 20) {
          atype -= 20;
          TLeafElement *leaf = (TLeafElement*)fLeaves.UncheckedAt(0);
          n *= leaf->GetLenStatic();
       }
       fInfo->PrintValue(GetName(),fAddress,atype,n);
       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);
          fInfo->PrintValue(GetName(),fAddress,atype,n);
       } else {
          fInfo->PrintValue(GetName(),fObject,fID,-1);
       }
       return;
     }
     return;
  }
   if (fType == 3) {
      printf(" %-15s = %dn",GetName(),fNdata);
   } else if (fType == 31) {
      TClonesArray *clones = (TClonesArray*)fObject;
      fInfo->PrintValueClones(GetName(),clones,fID,fOffset);
   } else {
      fInfo->PrintValue(GetName(),fObject,fID,-1);
   }
}

//______________________________________________________________________________
 void TBranchElement::ReadLeaves(TBuffer &b)
{
// Read buffers for this branch

  if (fTree->GetMakeClass()) {
     if (fType == 3) {    //top level branch of a TClonesArray
       Int_t *n = (Int_t*)fAddress;
       b >> n[0];
       fNdata = n[0];
       return;
     } else if (fType == 31) {    // sub branch of a TClonesArray
       fNdata = fBranchCount->GetNdata();
       Int_t atype = fStreamerType;
       if (atype > 34) return;
       if (!fAddress) return;
       Int_t n = fNdata;
       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;}
       }
       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;}
          }
       } else {
          fNdata = 1;
          if (fAddress) {
             fInfo->ReadBuffer(b,fObject,fID);
          } else {
             fNdata = 0;
          }
       }
       return;
     }
  }

  if (fType <=2 && TestBit(kBranchObject)) {
     b.MapObject((TObject*)fObject);
  }

  if (fType == 4) {           // STL vector/list of objects
     //printf ("STL split mode not yet implementedn");
  } else if (fType == 41) {    // sub branch of an STL class
    //char **ppointer = (char**)fAddress;
  } else if (fType == 3) {    //top level branch of a TClonesArray
    Int_t n;
    b >> n;
    fNdata = n;
    TClonesArray *clones = (TClonesArray*)fObject;
    if (!clones) 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;
    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;
    fInfo->ReadBuffer(b,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           = gROOT->GetClass(fClassName.Data())->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::SetAddress(void *add)
{
//*-*-*-*-*-*-*-*Set address of this branch*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*            ====================
//

   //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 = gROOT->GetClass(fClassName.Data());
   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=%lx, fInfo=%s, version=%dn",GetName(),fClassName.Data(),fParentName.Data(),fID,fType,nbranches,(Long_t)add,fInfo->GetName(),fClassVersion);
   }
   fAddress = (char*)add;
   if (fTree->GetMakeClass()) {
      if (fID >= 0) {
         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 a fake class
            if (!cl->GetClassInfo()) SetBit(kDeleteObject);
            fObject = (char*)cl->New();
            *ppointer = fObject;
         }
      } else {
         //Remember if we build an object of a fake class
         if (!cl->GetClassInfo()) SetBit(kDeleteObject);
         fObject = (char*)cl->New();
      }
      if (!fAddress) fAddress = (char*)&fObject;
   } else {
      fObject = fAddress;
   }

   //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;
         } else {
            TClonesArray **ppointer;
            ppointer = (TClonesArray**)fAddress;
            fObject = (char*)*ppointer;
         }
         if (!fObject) fAddress = 0;
      }
      TClass *clm = gROOT->GetClass(fClonesName.Data());
      if (clm) {
			clm->BuildRealData(); //just in case clm derives from an abstract class
			clm->GetStreamerInfo();
		}
      if (!fAddress) {
         //SetBit(kDeleteObject);
         fObject = (char*)new TClonesArray(fClonesName.Data());
         fAddress = (char*)&fObject;
      }
   }

   if (fType == 31) {
      if (fClassName != fParentName) {
         TClass *clparent = gROOT->GetClass(GetParentName());
         Int_t mOffset = 0;
         Int_t baseOffset = 0;
         TClass *clm = gROOT->GetClass(GetClassName());
         TStreamerInfo *binfo = clparent->GetStreamerInfo();
         if (clparent != clm) {
            char pname[kMaxLen];
            strcpy(pname,GetName());
            char *clast = (char*)strrchr(pname,'.');
            if (clast) {
               *clast = 0;
               char *clast2 = (char*)strrchr(pname,'.');
               if (clast2) {
                  binfo->GetStreamerElement(clast2+1,mOffset);
                  *clast2 = 0;
                  char *clast3 = (char*)strrchr(pname,'.');
                  if (clast3) {
                     TStreamerElement *el3 = binfo->GetStreamerElement(clast3+1,mOffset);
                     if (el3) {
                        Int_t mOffset2 = 0;
                        el3->GetClassPointer()->GetStreamerInfo()->GetStreamerElement(clast2+1,mOffset2);
                        mOffset += mOffset2;
                     }
                  }
               }   
               if (!clparent->GetBaseClass(clm)) fOffset = mOffset;
               if (!mOffset) {
                  if (clparent->GetBaseClass(clm)) {
                     baseOffset = clparent->GetBaseClassOffset(clm);
                     if (baseOffset < 0) baseOffset = 0; 
                     fOffset = baseOffset;                 
                  }
               }
            }
         }
      }
   }
   if (nbranches == 0) return;
   for (Int_t i=0;i<nbranches;i++)  {
      TBranchElement *branch = (TBranchElement*)fBranches[i];
      Int_t nb2 = branch->GetListOfBranches()->GetEntries();
      Int_t id = branch->GetID();
      Int_t mOffset = 0;
      Int_t baseOffset = 0;
      Int_t memberOffset = 0;
      TClass *clparent = gROOT->GetClass(branch->GetParentName());
      if (!clparent) clparent = cl;
      TClass *clm = gROOT->GetClass(branch->GetClassName());
      TStreamerInfo *binfo = clparent->GetStreamerInfo();
      //if sub-branch is a class deriving from the class of this branch
      //or a member of the class, one must add the base class offset
//printf("i=%d, clm=%s,clparent=%s, branch=%s, fType=%d, binfo=%sn",i,clm->GetName(),clparent->GetName(),branch->GetName(),fType,binfo->GetName());
 
         if (clparent != clm) {
         char pname[kMaxLen];
         strcpy(pname,branch->GetName());
         char *clast = (char*)strrchr(pname,'.');
         if (clast) {
            *clast = 0;
            char *clast2 = (char*)strrchr(pname,'.');
            if (clast2) binfo->GetStreamerElement(clast2+1,mOffset);
            if (fType == 2 && !clparent->GetBaseClass(clm)) memberOffset = mOffset;
            if (fType == 1) {
               binfo->GetStreamerElement(pname,memberOffset);
            }
            if (!branch->GetType() && !mOffset) {
               if (clparent->GetBaseClass(clm)) {
                  baseOffset = clparent->GetBaseClassOffset(clm);
                  if (baseOffset < 0) baseOffset = 0;                  
               }
            }
         }
      }
      if (nb2 > 0) { 
         TStreamerInfo *info = branch->GetInfo();
         if (info) {
            Int_t *leafOffsets = info->GetOffsets();
            if (leafOffsets) {
               branch->SetAddress(fObject + leafOffsets[id] + baseOffset);
            } else {
               Error("SetAddress","info=%s, leafOffsets=0",info->GetName());
            }
         } else {
            Error("SetAddress","branch=%s, info=0",branch->GetName());
         }
      } else {
         branch->SetAddress(fObject + baseOffset +memberOffset);
      }
   }
}

//______________________________________________________________________________
 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

   fBasketSize = buffsize;
   Int_t nbranches = fBranches.GetEntriesFast();
   for (Int_t i=0;i<nbranches;i++)  {
      TBranch *branch = (TBranch*)fBranches[i];
      branch->SetBasketSize(buffsize);
   }
}

//______________________________________________________________________________
 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);
}

//______________________________________________________________________________
 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;
   for (Int_t i=0;i<ndata;i++) {
      elem = (TStreamerElement*)elems[i];
     if (gDebug > 1) printf("Unroll name=%s, cltop=%s, cl=%s, i=%d, elem=%s, splitlevel=%d, btype=%d n",name,cltop->GetName(),cl->GetName(),i,elem->GetName(),splitlevel,btype);
     if (elem->IsA() == TStreamerBase::Class()) {
         clbase = gROOT->GetClass(elem->GetName());
         //here one should consider the case of a TClonesArray with a class
         //deriving from an abstract class
         //if ((cltop != cl) && (clbase->Property() & kIsAbstract)) return -1;
         //if (clbase->Property() & kIsAbstract) return -1;
         if (clbase->Property() & kIsAbstract) {
            if (cl->InheritsFrom("TCollection")) unroll = -1;
         }
         if (gDebug > 1) printf("Unrolling base class, cltop=%s, clbase=%sn",cltop->GetName(),clbase->GetName());
         if (unroll < 0 && btype != 31) return -1;
         else unroll = Unroll(name,cltop,clbase,basketsize,splitlevel-1,btype);
         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->SetParentName(cltop->GetName());
            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 > 1) printf("Unrolling object class, cltop=%s, clbase=%sn",cltop->GetName(),clbase->GetName());
            if (elem->CannotSplit())    unroll = -1;
            else unroll = Unroll(branchname,cltop,clbase,basketsize,splitlevel-1,btype);
            if (unroll < 0) {
               branch = new TBranchElement(branchname,info,jd,0,basketsize,0,btype);
               branch->SetParentName(cltop->GetName());
               fBranches.Add(branch);
            }
         } else {
            if (elem->GetClassPointer() == TClonesArray::Class()) {
               //process case of a TClonesArray in a derived class
               char *pointer = fBranchPointer + elem->GetOffset();
               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->SetParentName(cltop->GetName());
            fBranches.Add(branch);
         }
      }
      jd++;
   }
   return 1;
}


ROOT page - Class index - 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.