#ifndef TCOMETRawEvent_hxx_seen #define TCOMETRawEvent_hxx_seen #include #include #include #include #include "IDataVector.hxx" #include "IHandle.hxx" #include "IMidasBank.hxx" #include "IRawDataHeader.hxx" #include "Demangle.hxx" #define TCOMET_RAW_EVENT_TITLE "Raw Event" namespace COMET { class IMidasEventParser; class ICOMETRawEvent; } /// The TCOMETRawData class is the I/O container class for all DAQ /// banks. It can only hold objects that are, or inherit from, /// IMidasBank. This is ensured by the AdoptMidasBank method. /// /// All banks from the DAQ are initially encapsulated within generic /// IMidasBank objects. In this form they only give access to generic /// information for example the name of the MIDAS bank they came from, /// the size of the data and raw uninterpreted data itself. This /// class makes use of a proxy registration system /// IMidasBankProxyRegistry (q.v.) which allows it to "promote" these /// generic data objects into ones that give full interpreted access /// to the data. class COMET::ICOMETRawEvent : public IDataVector { public: typedef IDataVector::iterator iterator; typedef IDataVector::const_iterator const_iterator; ICOMETRawEvent(); explicit ICOMETRawEvent(const char* name, const IRawDataHeader& header = IRawDataHeader(), const char* title = TCOMET_RAW_EVENT_TITLE); /// This constructor is used by IMidasFile to create a ICOMETRawEvent from /// file. Typical code to create a IMidasFile, connect it to a file, and /// then loop sequentially returning TCOMETRawEvents is as follows:- /// /// \code /// COMET::IMidasFile mf; /// mf.Open("/home/west/test_data/run01854.mid"); /// while ( COMET::ICOMETRawEvent* re = mf.ReadRawEvent() ) { /// // Process event and then discard it. /// re->Print(); /// delete re; /// } /// \endcode /// /// This is also indirectly used by cometEventLoop (through the /// IVInputFile::NextEvent interface) to create a ICOMETEvent. The NextEvent /// method calls ReadRawEvent() to generate a ICOMETRawEvent object using this /// constructor, and the raw event is then added to a new ICOMETEvent. ICOMETRawEvent(const COMET::IMidasEventParser& mep, const char* name, const char* title = TCOMET_RAW_EVENT_TITLE); virtual ~ICOMETRawEvent(); Int_t GetEventSize() const { return fEventSize; } const IRawDataHeader& GetHeader() const { return fHeader; } /// Fill the header using the oaRawEvent context setters. If oaRawEvent /// is not available, this will return false. bool FillHeader(); /// Print contents to COMETLog void Print(const Option_t* opt = "") const; /// This member method template handles type conversions and helps to /// insure type safety. It is modelled on the /// /// \code /// template COMET::IHandle Get(const char* name=".") const /// \endcode /// /// but that method can neither be used nor overridden as the semantics /// are different in several regards:- ///
    ///
  1. The user may wish to access a bank either by MIDAS bank name /// or by object type, i.e. class (and recall that multiple bank names can /// map to a single class). /// /// In order to address this the second argument is /// /// \code ///Bool_t byType /// \endcode ///
      ///
    • - if true, name is assumed to be a class name ///
    • - if false, name is assumed to be a MIDAS bank name ///
    /// ///
  2. There is a degeneracy for example there can be multiple banks of /// the same type and access has to be provided to them all. /// /// In order to address this the third argument is /// /// \code ///IHandle startAfter /// \endcode ///
      ///
    • - if NULL, pointer start fresh search ///
    • - if non-NULL, handle resume search after handle ///
    /// ///
  3. Searching is constrained to the local container of banks, /// hierarchical searching following a Unix style directory structure is /// not supported or required. ///
/// There are some "convenience" interfaces to this function so that the /// user never has to explicitly supply the default value for any /// argument. /// /// Use of this method may trigger internal promotion of IMidasBank /// objects to their true class. This should be transparent (note this /// method claims to be constant, and logically is). For more details see /// the IMidasBankProxyRegistry. /// /// If the name is not found in the event, then this returns a NULL /// pointer. If name is found but cannot be converted to the request /// class, EBadConversion is thrown /// /// A typical usage might look something like this: /// /// \code /// myFunc(ICOMETRawEvent& revt) { /// // Get first IDemo1Bank object /// IHandle h /// = revt.GetMidasBank("COMET::IDemo1Bank"); /// while ( h ) { /// std::cout << "Found " << h->GetName() << std::endl; /// // Get next IDemo1Bank object /// h = revt.GetMidasBank("COMET::IDemo1Bank",h); /// } /// } /// \endcode template COMET::IHandle GetMidasBank(const char* name, Bool_t byType, IHandle startAfter) const { // Make sure all the data is promoted unless accessing at the generic level. // This should allow generic access without generating warnings when the // oaRawEvent library isn't present. if (typeid(T) != typeid(COMET::IMidasBank)) this->PromoteMidasBanks(); const_iterator itr(this->IDataVector::begin()), itrEnd(this->IDataVector::end()); // Skip forward if requested if ( startAfter ) { IMidasBank* start_obj = dynamic_cast(&(*startAfter)); for (; itr != itrEnd; ++itr) { if ( start_obj == *itr ) { ++itr; break; } } } // Scan the container for (; itr != itrEnd; ++itr) { IMidasBank* mb = dynamic_cast(*itr); if ( ! mb ) continue; // This should not happen - all elements should be IMidasBank* const char* mb_name = byType ? Tools::Demangle(typeid(*mb)).c_str() : mb->GetName(); if ( strlen(name) == 0 || strcmp(name,mb_name) == 0 ) { T* t = dynamic_cast(mb); // Don't warn about conversion failures if accepting every bank name. if ( strlen(name) == 0 && !t ) continue; if (!t) { COMETWarn(" Bank: " << mb->GetName() << " -- Cannot convert from" << " from \"IMidasBank*\"" << " to \"" << typeid(T).name() << "\""); throw EBadConversion(); } return IHandle(t,false); } } return IHandle(NULL); } /// @{ Convenience functions so that default values never need to be /// explicitly supplied. See full GetMidasBank documentation for /// definitions. template COMET::IHandle GetMidasBank(const char* name, Bool_t byType = false) const { return GetMidasBank(name,byType,IHandle()); } template COMET::IHandle GetMidasBank(const char* name, IHandle startAfter) const { return GetMidasBank(name,false,startAfter); } /// @} /// Return a reference to a IMidasBank or subclass object (see the /// GetMidasBank() method for discussion of the call arguments). If /// the object is not found, then an ENoSuchElement exception will be /// thrown and if the object cannot be dynamic cast to the requested class /// an EBadConversion will be thrown. A typical usage might look /// something like this: /// /// \code /// myFunc(ICOMETRawEvent& revt) { /// // Try to find a IDemo1Bank object /// try /// IDemo1Bank& rd1b /// = rev.UseMidasBank("COMET::IDemo1Bank"); /// std::cout << "Found " << h->GetName() << std::endl; /// catch (ENoSuchElement) { /// std::cout << "object is not found" << std::endl; /// } /// } /// \endcode template T& UseMidasBank(const char* name, Bool_t byType, IHandle startAfter ) const { IHandle object(GetMidasBank(name)); if (!object) throw ENoSuchElement(); return *object; } /// @{ Convenience functions so that default values never need to be /// explicitly supplied. See full UseMidasBank template for parameter /// definitions. template T& UseMidasBank(const char* name, Bool_t byType = false) const { return UseMidasBank(name,byType,IHandle()); } template T& UseMidasBank(const char* name, IHandle startAfter) const { return UseMidasBank(name,false,startAfter); } /// @} /// Take ownership of a generic IMidasBank void AdoptMidasBank(IMidasBank* component) { this->IDataVector::AddDatum(component); fHasUnpromotedBanks = true; } /// Scan container and promote banks. Its declared as a const method /// as conceptually it is even though it may sneakly replace one set of /// objects with another. void PromoteMidasBanks(Bool_t warn = true) const; /// @{Override methods in the base TObject class. virtual void ls(Option_t* opt = "") const; /// @} private: /// Block methods inherited from IDataVector that would allow user /// to insert objects that are not IMidasBank or their subclasses void NotImplemented(const char* method) const; virtual void AddDatum(COMET::IHandle< COMET::IDatum > handle, const char *name=NULL) {this->NotImplemented("AddDatum");} virtual void AddDatum(IDatum *val, const char *name=NULL) {this->NotImplemented("AddDatum");} virtual void push_back(IDatum *data) {this->NotImplemented("push-back");} virtual iterator insert (iterator position, IDatum *data) {this->NotImplemented("iterator"); return position;} /// Set name based on header void SetNameFromHeader(); /// Global information for the raw event IRawDataHeader fHeader; /// Event size in bytes from the 3rd word of the MIDAS event header Int_t fEventSize; /// Global information for the run (updated when begin/end run record encountered). static Int_t fgRun; /// Optimisation: don't waste time looking for banks to promote if false mutable Bool_t fHasUnpromotedBanks; //! Do not save ClassDef(ICOMETRawEvent,2) }; #endif