--- /dev/null
+#include "TObjArray.h"
+#include "TFile.h"
+#include "TTree.h"
+#include "TBrowser.h"
+#include "TTreeStream.h"
+
+
+ClassImp(TTreeDataElement)
+ClassImp(TTreeStream)
+ClassImp(TTreeSRedirector)
+
+/*
+ marian.ivanov@cern.ch
+ //
+ ------------------------------------------------------------------------------------------------
+ TTreeStream
+ Standard stream (cout) like input for the tree
+ Run and see TTreeStreamer::Test() - to see TTreeStreamer functionality
+ ------------------------------------------------------------------------------------------------
+ //
+ -------------------------------------------------------------------------------------------------
+ TTreeSRedirector
+ Redirect file to different TTreeStreams
+ Run and see TTreeSRedirector::Test() as an example of TTreeSRedirectorer functionality
+ //
+*/
+
+
+void TTreeStream::Test()
+{
+ //
+ //
+ TFile *ftest = new TFile("teststreamer.root","recreate");
+ if (!ftest) ftest = new TFile("teststreamer.root","new");
+ //
+ //create to streems Tree1 and Tree2
+ TTreeStream stream1("Tree1");
+ TTreeStream stream2("Tree2");
+ //
+ Char_t ch='s';
+ Float_t f=3.;
+ Float_t f2=1;
+ TObject *po = new TObject;
+ TObject *po2 = new TObject;
+ for (Int_t i=0;i<100000;i++) {
+ f=i*100;
+ po->SetUniqueID(i);
+ po2->SetUniqueID(i*100);
+ ch=i%120;
+ //
+ // Stream the data
+ // The data layout of stream is defined during first invocation of streamer.
+ // Endl is the trigger which define the end of structure.
+ //
+ // The name of branch can be specified using strings with = at the the end
+ // if string is not specified automatic convention is u (sed B0, B1, ...Bn)
+ stream1<<"i="<<i<<"ch="<<ch<<"f="<<f<<"po="<<po<<"\n";
+ f = 1./(100.1+i);
+ f2 = -f;
+ //3.) just another example - we can fill the same tree with different objects
+ //
+ stream2<<f<<po<<"\n";
+ stream2<<f2<<po2<<"\n";
+ }
+ //
+ //4.) Close the streeamers (Write the streamed tree's to the file) and close the corresponding file.
+ //
+ stream1.Close();
+ stream2.Close();
+ ftest->Close();
+ delete ftest;
+ //
+ //5.) and now see results in file tteststreamer.root
+}
+
+
+
+void TTreeSRedirector::Test()
+{
+ //
+ //Example test function to show functionality of TTreeSRedirector
+ //
+ //
+ //1.)create the redirector associated with file (testredirector.root)
+ //
+ //
+ TTreeSRedirector *pmistream= new TTreeSRedirector("testredirector.root");
+ TTreeSRedirector &mistream = *pmistream;
+ Char_t ch='s';
+ Float_t f=3.;
+ Float_t f2=1;
+ TObject *po = new TObject;
+ TObject *po2 = new TObject;
+ for (Int_t i=0;i<100000;i++) {
+ f=i*100;
+ po->SetUniqueID(i);
+ po2->SetUniqueID(i*100);
+ ch=i%120;
+ //
+ //2.) create the tree with identifier specified by first argument
+ // layout specified by sequence of arguments
+ // Tree identifier has to be specified as first argument !!!
+ // if the tree and layout was already defined the consistency if layout is checked
+ // if the data are consisten fill given tree
+ // the name of branch can be specified using strings with = at the the end
+ // if string is not specified use automatic convention B0, B1, ...Bn
+ mistream<<"TreeIdentifier"<<"i="<<i<<"ch="<<ch<<"f="<<f<<"po="<<po<<"\n";
+ f = 1./(100.1+i);
+ f2 = -f;
+
+ //3.) just another example - we can fill the same tree with different objects
+ //
+ mistream<<"TreeK"<<f<<po<<"\n";
+ mistream<<"TreeK"<<f2<<po2<<"\n";
+ }
+ //
+ //4.) write the streamed tree's to the file and close the corresponding file in destructor
+ //
+ delete pmistream;
+ //
+ //5.) and now see results in file testredirector.root
+}
+
+
+
+
+
+
+TTreeSRedirector::TTreeSRedirector(const char *fname){
+ //
+ //
+ fFile = new TFile(fname,"recreate");
+ if (!fFile){
+ fFile = new TFile(fname,"new");
+ }
+ fDataLayouts =0;
+
+}
+
+TTreeSRedirector::~TTreeSRedirector(){
+ //
+ //
+ Close(); //write the tree to the selected file
+ fFile->Close();
+ delete fFile;
+}
+
+TTreeStream & TTreeSRedirector::operator<<(Int_t id)
+{
+ //
+ // return reference to the data layout with given identifier
+ // if not existing - creates new
+ if (!fDataLayouts) fDataLayouts = new TObjArray(10000);
+ TTreeStream *clayout=0;
+ Int_t entries = fDataLayouts->GetEntriesFast();
+ for (Int_t i=0;i<entries;i++){
+ TTreeStream * layout = (TTreeStream*)fDataLayouts->At(i);
+ if (!layout) continue;
+ if (layout->fId==id) {
+ clayout = layout;
+ break;
+ }
+ }
+ if (!clayout){
+ char chname[100];
+ sprintf(chname,"Tree%d",id);
+ clayout = new TTreeStream(chname);
+ clayout->fId=id;
+ fDataLayouts->AddAt(clayout,entries);
+ }
+ return *clayout;
+}
+
+
+TTreeStream & TTreeSRedirector::operator<<(const char* name)
+{
+ //
+ // return reference to the data layout with given identifier
+ // if not existing - creates new
+ if (!fDataLayouts) fDataLayouts = new TObjArray(10000);
+ TTreeStream *clayout=0;
+ Int_t hash = TMath::Hash(name);
+ Int_t entries = fDataLayouts->GetEntriesFast();
+ for (Int_t i=0;i<entries;i++){
+ TTreeStream * layout = (TTreeStream*)fDataLayouts->At(i);
+ if (!layout) continue;
+ if (layout->fHash==hash) {
+ clayout = layout;
+ break;
+ }
+ }
+ if (!clayout){
+ clayout = new TTreeStream(name);
+ clayout->fId=-1;
+ clayout->SetName(name);
+ clayout->fHash = hash;
+ fDataLayouts->AddAt(clayout,entries);
+ }
+ return *clayout;
+}
+
+
+
+
+void TTreeSRedirector::Close(){
+ //
+ //
+ Int_t entries = fDataLayouts->GetEntriesFast();
+ for (Int_t i=0;i<entries;i++){
+ TTreeStream * layout = (TTreeStream*)fDataLayouts->At(i);
+ if (layout){
+ if (layout->fTree) layout->fTree->Write();
+ }
+ }
+}
+
+
+
+//-------------------------------------------------------------
+TTreeDataElement:: TTreeDataElement(Char_t type){
+ //
+ //
+ fType = type;
+ fDType = 0;
+ fClass = 0;
+ fPointer= 0;
+}
+TTreeDataElement:: TTreeDataElement(TDataType* type){
+ //
+ //
+ fType = 0;
+ fDType = type;
+ fClass = 0;
+ fPointer= 0;
+}
+TTreeDataElement:: TTreeDataElement(TClass* cl){
+ //
+ //
+ fType = 0;
+ fDType = 0;
+ fClass = cl;
+ fPointer= 0;
+}
+
+//-------------------------------------------------------------------
+TTreeStream::TTreeStream(const char *treename):TNamed(treename,treename){
+ fElements =0;
+ fTree =0;
+ fCurrentIndex =0;
+ fNextName="";
+ fNextNameCounter=0;
+ fTree = new TTree(treename, treename);
+}
+
+TTreeStream::~TTreeStream()
+{
+ fElements->Delete();
+ fBranches->Clear();
+ delete fElements;
+ delete fBranches;
+}
+
+void TTreeStream::Close()
+{
+ //
+ fTree->Write();
+}
+
+Int_t TTreeStream::CheckIn(Char_t type, void *pointer)
+{
+ if (!fElements) fElements = new TObjArray(1000);
+ TTreeDataElement* element = (TTreeDataElement*)fElements->At(fCurrentIndex);
+ if (!element) {
+ element = new TTreeDataElement(type);
+ //
+ char name[1000];
+ if (fNextName.Length()>0){
+ if (fNextNameCounter==0){
+ sprintf(name,"%s",(const char*)fNextName);
+ }
+ if (fNextNameCounter>0){
+ sprintf(name,"%s%d",(const char*)fNextName,fNextNameCounter);
+ }
+ }
+ else{
+ sprintf(name,"B%d.",fCurrentIndex);
+ }
+ element->SetName(name);
+ //
+ element->SetPointer(pointer);
+ fElements->AddAt(element,fCurrentIndex);
+ fCurrentIndex++;
+ return 0; //new element added
+ }
+ if (element->GetType()!=type){
+ fStatus++;
+ return 1; //mismatched data element
+ }
+ element->SetPointer(pointer);
+ fCurrentIndex++;
+ return 0;
+}
+
+Int_t TTreeStream::CheckIn(TObject *o){
+ //
+ //
+ if (!o) return 0;
+ if (!fElements) fElements = new TObjArray(1000);
+ TTreeDataElement* element = (TTreeDataElement*)fElements->At(fCurrentIndex);
+ if (!element) {
+ element = new TTreeDataElement(o->IsA());
+ //
+ char name[1000];
+ if (fNextName.Length()>0){
+ if (fNextNameCounter==0){
+ sprintf(name,"%s",(const char*)fNextName);
+ }
+ if (fNextNameCounter>0){
+ sprintf(name,"%s%d",(const char*)fNextName,fNextNameCounter);
+ }
+ }
+ else{
+ sprintf(name,"B%d",fCurrentIndex);
+ }
+ element->SetName(name);
+
+ element->SetPointer(o);
+ fElements->AddAt(element,fCurrentIndex);
+ fCurrentIndex++;
+ return 0; //new element added
+ }
+ if (element->fClass!=o->IsA()){
+ fStatus++;
+ return 1; //mismatched data element
+ }
+ element->SetPointer(o);
+ fCurrentIndex++;
+ return 0;
+}
+
+void TTreeStream::BuildTree(){
+ //
+ //
+ if (fTree->GetEntries()>0) return;
+ fTree = new TTree(GetName(),GetName());
+ Int_t entries = fElements->GetEntriesFast();
+ fBranches = new TObjArray(entries);
+
+ for (Int_t i=0;i<entries;i++){
+ //
+ TTreeDataElement* element = (TTreeDataElement*)fElements->At(i);
+ char bname1[1000];
+ if (element->GetName()[0]==0){
+ sprintf(bname1,"B%d",i);
+ }
+ else{
+ sprintf(bname1,element->GetName());
+ }
+ if (element->fClass){
+ TBranch * br = fTree->Branch(bname1,element->fClass->GetName(),&(element->fPointer));
+ fBranches->AddAt(br,i);
+ }
+ if (element->GetType()>0){
+ char bname2[1000];
+ sprintf(bname2,"B%d/%c",i,element->GetType());
+ TBranch * br = fTree->Branch(bname1,element->fPointer,bname2);
+ fBranches->AddAt(br,i);
+ }
+ }
+}
+
+void TTreeStream::Fill(){
+ //
+ //
+ if (fTree) {
+ Int_t entries=fElements->GetEntriesFast();
+ if (entries>fTree->GetNbranches()) BuildTree();
+ for (Int_t i=0;i<entries;i++){
+ TTreeDataElement* el = (TTreeDataElement*)fElements->At(i);
+ if (!el) continue;
+ if (!el->GetType()) continue;
+ TBranch * br = (TBranch*)fBranches->At(i);
+ if (br &&el){
+ if (el->GetType()) br->SetAddress(el->fPointer);
+ }
+ }
+ if (fStatus==0) fTree->Fill(); //fill only in case of non conflicts
+ fStatus=0;
+ }
+}
+
+TTreeStream & TTreeStream::Endl(){
+ if (fTree->GetNbranches()==0) BuildTree();
+ Fill();
+ fStatus =0;
+ fCurrentIndex=0;
+ return *this;
+}
+
+
+TTreeStream &TTreeStream::operator<<(Char_t *name)
+{
+ //
+ //
+ //
+ //Endl
+ if (name[0]=='\n'){
+ return Endl();
+ }
+ //
+ //if tree was already defined ignore
+ if (fTree->GetEntries()>0) return *this;
+ //check branch name if tree was not
+ //
+ Int_t last=0;
+ for (last=0;;last++){
+ if (name[last]==0) break;
+ }
+
+ if (last>0&&name[last-1]=='='){
+ fNextName = name;
+ fNextName[last-1]=0;
+ fNextNameCounter=0;
+ }
+ return *this;
+}
+
--- /dev/null
+#ifndef TTREESTREAM_H
+#define TTREESTREAM_H
+///////////////////////////////////////////////////////////////////////////////
+// //
+// TTreeSRedirector //
+
+#include "TObject.h"
+#include "TString.h"
+class TFile;
+class TObjArray;
+class TTree;
+class TDataType;
+
+class TTreeDataElement: public TNamed {
+ friend class TTreeStream;
+ public:
+ TTreeDataElement(Char_t type);
+ TTreeDataElement(TDataType* type);
+ TTreeDataElement(TClass* cl);
+ void SetPointer(void* pointer) {fPointer=pointer;}
+ Char_t GetType() const {return fType;}
+ protected:
+ TString fName; // name of the data element
+ Char_t fType; // type of data element
+ TDataType *fDType; //data type pointer
+ TClass *fClass; //data type pointer
+ void * fPointer; // pointer to element
+ ClassDef(TTreeDataElement,1)
+};
+
+class TTreeStream: public TNamed {
+ friend class TTreeSRedirector;
+public:
+ TTreeStream(const char *treename);
+ ~TTreeStream();
+ void Close();
+ static void Test();
+ Int_t CheckIn(Char_t type, void *pointer);
+ //Int_t CheckIn(const char *type, void *pointer);
+ Int_t CheckIn(TObject *o);
+ void BuildTree();
+ void Fill();
+ TTreeStream& Endl();
+ //
+ TTreeStream &operator<<(Bool_t &b){CheckIn('B',&b);return *this;}
+ TTreeStream &operator<<(Char_t &c){CheckIn('B',&c);return *this;}
+ TTreeStream &operator<<(UChar_t &c){CheckIn('b',&c);return *this;}
+ TTreeStream &operator<<(Short_t &h){CheckIn('S',&h);return *this;}
+ TTreeStream &operator<<(UShort_t &h){CheckIn('s',&h);return *this;}
+ TTreeStream &operator<<(Int_t &i){CheckIn('I',&i);return *this;}
+ TTreeStream &operator<<(UInt_t &i){CheckIn('i',&i);return *this;}
+ TTreeStream &operator<<(Long_t &l){CheckIn('L',&l);return *this;}
+ TTreeStream &operator<<(ULong_t &l){CheckIn('l',&l);return *this;}
+ TTreeStream &operator<<(Long64_t &l){CheckIn('L',&l);return *this;}
+ TTreeStream &operator<<(ULong64_t &l){CheckIn('l',&l);return *this;}
+ TTreeStream &operator<<(Float_t &f){CheckIn('F',&f);return *this;}
+ TTreeStream &operator<<(Double_t &d){CheckIn('D',&d);return *this;}
+ TTreeStream &operator<<(TObject*o){CheckIn(o);return *this;}
+ TTreeStream &operator<<(Char_t *name);
+ protected:
+ //
+ TObjArray *fElements; //array of elements
+ TObjArray *fBranches; //pointers to branches
+ TTree *fTree; //data storage
+ Int_t fCurrentIndex; //index of current element
+ Int_t fId; //identifier of layout
+ Int_t fHash; //hash value of string
+ TString fNextName; //name for next entry
+ Int_t fNextNameCounter; //next name counter
+ Int_t fStatus; //status of the layout
+ ClassDef(TTreeStream,1)
+};
+
+
+
+class TTreeSRedirector: public TObject {
+public:
+ TTreeSRedirector(const char *fname);
+ ~TTreeSRedirector();
+ void Close();
+ static void Test();
+ virtual TTreeStream &operator<<(Int_t id);
+ virtual TTreeStream &operator<<(const char *name);
+ private:
+ TFile* fFile; //file
+ TObjArray *fDataLayouts; //array of data layouts
+ ClassDef(TTreeSRedirector,1)
+};
+
+
+
+
+#endif