#ifndef INCLUDE_TSEED_H #define INCLUDE_TSEED_H #include "TSingleEntryTree.h" #include class TClonesArray; namespace seed { class TSeedABC: public TObject { friend class TSeedList; friend class TEventSample; protected: TSeedABC(const Char_t* cName, seed::TEventSample * pES=NULL); // clean up virtual ~TSeedABC() {}; public: // returns whether this TSeed is used for reading / writing inline Bool_t IsEnabled() const { return fBEnabled; }; void Enable(Bool_t bEnable = kTRUE); virtual Bool_t FillSeedData(TSingleEntryTree & tree, const Int_t iEventNo); inline Long_t GetNumberOfFilledObjects() const { return fINumObjCreatedTotal; }; Long_t Size() const; // function returning the type of objects created by the derived TSeed inline virtual const Char_t* GetClassName() const = 0; virtual const Char_t * GetName() const { return fName; }; protected: TSeedABC* GetSeedData(const Char_t* strLabel); void SetFillOwner(TSingleEntryTree * tree, TClonesArray * const * pCA); // is called at beginning of new TTree, to be overloaded for derived classes' init virtual Bool_t Init(seed::TSingleEntryTree& tree); TBranch* CreateBranch(TClonesArray ** ppCA, TTree * pTree); virtual Bool_t PreFillSeedData( std::list< seed::TSeedABC* >& callStack, Int_t iEventNo); // called right before TEventSample's TTree::Fill inline virtual void PreFill(){ fINumObjCreatedTotal += fINumObjCreatedEvent; }; protected: TClonesArray * const *fPCA; // temporary address of currently filled/read TCA seed::TSingleEntryTree* fSET; // currently read seed::TSingleEntryTree = ntuple Bool_t fBEnabled; // true: this seed has to process / read data ULong_t fINumObjCreatedTotal; // number of objects put into fPCA ULong_t fINumObjCreatedEvent; // number of objects created during the current entry std::list < seed::TSeedABC* > * fCallStack; // call stack for FillSeedData const Char_t* fName; // name of the seed = name of corresponding branch ClassDef(TSeedABC, 0) // abstract base class for data access objects }; template < class T > class TSeed: public TSeedABC { public: // create a seed::TSeed for reading data from a seed::TEventSample TSeed(const Char_t* cName, seed::TEventSample * pES = NULL): TSeedABC(cName, pES) {}; // clean up virtual ~TSeed() {}; T * NewEntry(); T * GetEntry(const ULong_t iIdx); inline virtual const Char_t* GetClassName() const { return T::Class()->GetName(); }; // access the iIndex'th element of the TClonesArray T & operator[](Int_t iIndex); // in case there is only one object per entry T * operator -> (); }; template < class T > T* TSeed < T >::NewEntry() { if (!fPCA || !*fPCA) { Error("NewEntry", "TClonesArray not initialized! (Contact manufacturer, " "this is not supposed to happen.)"); TEventSample::AddError(); return NULL; }; return (T *) new( ((**fPCA)[fINumObjCreatedEvent++])) T(); } template < class T > T* TSeed < T >::GetEntry(const ULong_t iIdx) { if (fINumObjCreatedEvent<=iIdx) return NULL; return (T *) ((**fPCA)[fINumObjCreatedEvent++]); } template < class T > T & TSeed < T >::operator[](Int_t iIndex) { return *(T *) (*fPCA)->At(iIndex); }; template < class T > T * TSeed < T >::operator -> () { if (Size()>1) { Warning("operator ->","There is more than one entry in the seed data you " "are accessing by the operator ->! Consider using the array " "operator []."); TEventSample::AddWarning(); }; return (T *) (*fPCA)->At(0); }; /** ---- Macro definition for Seeds ---- Macro to generate the Seed for a given data class. The only method implementation not generated is LABEL::FillSeedData, as here the tree's branch has to be converted into the object's data. So you'll have to add this method by hand - if you forget this the compiler will complain about a not defined pure virtual FillSeedData method in the base class TSeedABC. This method fills its TClonesArray, or better: the object of type CLASSNAME themselves. To order a new list entry use NewEntry(), which returns a pointer to a CLASSNAME object - it's your job to feed the data from the tree into this object. And it should returns true if successful. Call the macro giving the data class's name and a label, preferrably somehow correlated to the data's branch name (or even better: Some name describing what that data is), as this label specifies an object's data source, e.g. MAKE_SEED( TCaloJet, TCone08Jet ) The static at the end of the class def creates the one and only object of this type, registering itself (via its constructor) with the singleton TSeedList. So every MAKE_SEED call included in the compiled code results in a "Seed-able" object (this is done automatically, so don't worry). For further explanations on how registering and object creation works have a look at the user guide :-). For the other methods see the base class TSeedABC. If somebody wants to "parse" this macro: a _QUOTE_(LABEL) makes (from the example given above) a '"JCCGJet"' (where the actual result is given within the ''), a _NAME2_(LABEL,something) results in the code 'CaloJetsomething', so it simply concats the characters. The derived Seed uses a unique namespace - nobody should access this object anyway - it just registers with seed::TSeedList when created. */ }// namespace seed #define MAKE_SEED( CLASSNAME, LABEL ) \ class LABEL: public seed::TSeed< CLASSNAME > \ { \ public:\ inline LABEL( seed::TEventSample* pES ): TSeed< CLASSNAME > (_QUOTE_(LABEL), pES) {\ if (!fPCA || ! *fPCA) Warning( _QUOTE_(LABEL)"(TEventSample*)",\ "Can't access data; is the Seed enabled?\n");\ TEventSample::AddWarning(); };\ virtual inline ~LABEL(){};\ Bool_t FillSeedData(seed::TSingleEntryTree &tree, const Int_t iEventNo) {\ Error("FillSeedData",\ "This method may not be called.\n");\ TEventSample::AddError(); \ return kFALSE; \ }; \ };\ class _NAME2_(LABEL,_Seed) : public seed::TSeed< CLASSNAME > \ { \ public: \ inline _NAME2_( LABEL , _Seed)(): TSeed< CLASSNAME >(_QUOTE_(LABEL)) {};\ inline virtual ~_NAME2_( LABEL , _Seed)() {}; \ Bool_t FillSeedData(seed::TSingleEntryTree &tree, const Int_t iEventNo); \ };\ namespace{ \ static _NAME2_( LABEL , _Seed) _NAME3_( seedGlObAlStAtIc, LABEL , _Seed); \ }; #endif