From: <ro...@us...> - 2003-09-16 11:49:17
|
Update of /cvsroot/nsclspectcl/SpecTcl/Filter In directory sc8-pr-cvs1:/tmp/cvs-serv3604 Modified Files: EventFilter.cpp EventFilter.h Log Message: 1. Put Output Event formatting into this base class so that derived classes don't have to do this each and every time. 2. Decouple the event format from the event output stream. Note that there can still be some structural improvmements to support output streams other than CXdrOutputStreams but that's easy enough to do later when the need arises. 3. Implement operator() so again, derived classes don't have to re-implement this each time. 4. Move the parameter name/id binding to Enable so that late binding is possible. 5. Added a few utility functions to refactor. Index: EventFilter.cpp =================================================================== RCS file: /cvsroot/nsclspectcl/SpecTcl/Filter/EventFilter.cpp,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** EventFilter.cpp 20 Jul 2003 00:14:52 -0000 1.7 --- EventFilter.cpp 16 Sep 2003 11:49:12 -0000 1.8 *************** *** 1,2 **** --- 1,3 ---- + /* EventFilter.cpp *************** *** 8,119 **** // Header Files. ! #include <vector> ! #include <string> ! #include "Histogrammer.h" #include "Parameter.h" #include "Event.h" #include "EventList.h" ! #include "EventFilter.h" ! #include "OutputEventStream.h" // Constructors. ! /* ! Problem with file name parsing: ! There is already a ParseFileName function in OutputEventStream. ! Don't want to put another in here as that would give two essentially identical functions that have to be maintained to give identical results (especially in the case where a default file is necessary. ! At the same time, I cannot call COutputEventStream::ParseFileName until the filter is enabled and the output event stream object is created. ! Hence, I hold onto the input file name until the output event stream is created and I am able to use its parser to set the file name. */ CEventFilter::CEventFilter() : m_fEnabled(kfFALSE), ! m_sFileName(""), // Initialized to default. ! m_pOutputEventStream((COutputEventStream*)kpNULL) { ! m_vParameterNames.clear(); } CEventFilter::CEventFilter(string& rFileName) : m_fEnabled(kfFALSE), m_sFileName(rFileName), ! m_pOutputEventStream((COutputEventStream*)kpNULL) { - m_vParameterNames.clear(); } ! /* ! CEventFilter::CEventFilter(COutputEventStream& rOutputEventStream) : ! m_fEnabled(false), ! m_sFileName("~/filteroutput.txt"), // Just a default. Will be reset. ! m_pOutputEventStream(rOutputEventStream) ! { ! // Allows the reuse of a previously defined output event stream. ! // Set the file name in the event filter to that already used in the output event stream. ! string sFileName = m_pOutputEventStream->getFileName(); ! setFileName(sFileName); ! } ! */ CEventFilter::~CEventFilter() { ! Disable(); } - // Operators. - CEventFilter& CEventFilter::operator=(const CEventFilter& rRhs) { - return *this; - } ! // Additional functions. ! void CEventFilter::Enable() { ! // Actually does a re-enable to reset the configuration with any new parameters and be on the safe side. ! Disable(); // Clear everything. May be redundant, especially when the file name is reset, but prevents a potential problem. ! m_pOutputEventStream = new COutputEventStream(m_sFileName, m_vParameterNames); // Constructor will call COutputEventStream::Open(). ! m_sFileName = m_pOutputEventStream->getFileName(); // Read back the parsed file name. ! //m_fEnabled = m_pOutputEventStream->Open(); // Can also set with m_pOutputEventStream->isActive(). // Open() will be done on creation. ! m_fEnabled = kfTRUE; } ! void CEventFilter::Disable() { // Must be consecutively callable. ! if(m_pOutputEventStream != (COutputEventStream*)kpNULL) { ! //m_pOutputEventStream->Close(); // Close() will be done on deletion. ! delete m_pOutputEventStream; // Deconstructor will call COutputEventStream::Close(). ! } ! m_pOutputEventStream = (COutputEventStream*)kpNULL; // Otherwise, delete would cause a SegFault later. ! m_fEnabled = kfFALSE; } ! void CEventFilter::setFileName(string& rFileName) { ! // Whenever this is called, a call to Enable() must be made for the filter to be used. ! Disable(); // Reset output event stream using new file name. (This Disable() call is unnecessary, but I'll leave it just to be explicit.) ! m_sFileName = rFileName; } ! std::string CEventFilter::getFileName() { ! return m_sFileName; } ! Bool_t CEventFilter::CheckEnabled() { ! return m_fEnabled; } ! Bool_t CEventFilter::CheckCondition(CEvent& rEvent) { ! // OVERRIDDEN BY SUB-CLASS. ! return kfTRUE; } ! void CEventFilter::FormatOutputEvent(CEvent& rEvent) { ! // OVERRIDDEN BY SUB-CLASS. ! //(*m_pOutputEventStream).ReceiveEvent(rEvent); } ! COutputEventStream& CEventFilter::AttachOutputEventStream(COutputEventStream& rOutputEventStream) { ! m_pOutputEventStream = &rOutputEventStream; ! return rOutputEventStream; // Returns the original, which should be the same. } ! COutputEventStream& CEventFilter::DetachOutputEventStream() { ! m_pOutputEventStream = (COutputEventStream*)kpNULL; ! return *m_pOutputEventStream; // Returns the original setting. } --- 9,388 ---- // Header Files. ! #include "EventFilter.h" #include "Histogrammer.h" #include "Parameter.h" #include "Event.h" #include "EventList.h" + #include "CXdrOutputStream.h" + #include "Globals.h" + #include "DictionaryException.h" + + #include <vector> + #include <string> + #include <string.h> + #include <stdlib.h> ! ! static const char* headerlabel = "header"; ! static const char* eventlabel = "event"; // Constructors. ! ! /*! ! Construct an event filter: ! - Enable is set to false. ! - The file name is set to a 'suitable default'. ! - The output stream is set to null initially. ! - Parameter names and id arrays are initially clear (this is done by ! the vector contructors). ! ! Output stream binding is done at enable time. */ CEventFilter::CEventFilter() : m_fEnabled(kfFALSE), ! m_sFileName(CEventFilter::DefaultFilterFilename()), // Initialized to default. ! m_pOutputEventStream((CXdrOutputStream*)kpNULL) { ! } + /*! + Construct an event filter: + - Enable is set false. + - The filename is set to the user specified filename. + - The output stream is set to null initially. + - Parameter names and ID arrays are initially clear (done by vector + constructors). + + Output stream binding is done at enable time. + \param rFilename (in): + The name of the file to use for the output event stream. + */ CEventFilter::CEventFilter(string& rFileName) : m_fEnabled(kfFALSE), m_sFileName(rFileName), ! m_pOutputEventStream((CXdrOutputStream*)kpNULL) { } ! /*! ! Destroy an output event stream. The following must be done: ! - Any existing output event file must be destroyed. + note that destruction implies file flush and close. + */ CEventFilter::~CEventFilter() { ! if(m_pOutputEventStream) { ! ! delete m_pOutputEventStream; ! } } ! /*! ! Enable the filter. This does a few things: ! - Translate parameters from names to ids. ! - Open the output filter file. ! - Set the enable flag true. ! ! \note If the filter is enabled already, it is disabled to close ! any existing output file etc. ! \note Parameter names with no mapping to a parameter id are ! silently discarded from the output stream, but remain in the ! list of named parameters in case they re-appear later in the ! lifetime of SpecTcl. ! ! */ ! void ! CEventFilter::Enable() { ! ! if(m_fEnabled) { ! Disable(); // Close any existing output file and ! ! } // ensure we're disabled on failure. ! ! NamesToIds(); // Translate the names. ! m_pOutputEventStream = new CXdrOutputStream(m_sFileName); ! FormatEventDescription(); // First record of each filter file. ! m_fEnabled = kfTRUE; } ! /*! ! Disable the filter. This involves: ! - Destroying any existing filter. ! - Setting the filter pointer to null. ! - Setting the enable flag false. ! ! */ ! void ! CEventFilter::Disable() { // Must be consecutively callable. ! delete m_pOutputEventStream; // No-OP if pointer is already null ! m_pOutputEventStream = (CXdrOutputStream*)kpNULL; // Mark no stream. ! m_fEnabled = kfFALSE; // We're disabled. } ! /*! ! Change the name of the output stream. ! If the filter is disable, this is just a matter of setting ! the appropriate member function. Otherwise, this means ! that the active filter stream will be re-directed to another ! file target. ! */ ! void ! CEventFilter::setFileName(string& rFileName) { ! if(m_fEnabled) { ! Disable(); // Close the old stream. ! } ! m_sFileName = rFileName; // Set the new filename. ! } ! /*! ! Function call operator with a list of events. ! This overridable member provides the default behavior ! for a filter on a list of events. For each event in the ! event list, the single event function call operator is called. ! ! \param rEvents (in) ! The list of events to process. Note that the event list is usually ! a fixed size entity that is terminated by a null pointer to an event. ! */ ! void ! CEventFilter::operator()(CEventList& rEvents) ! { ! CEventListIterator i; ! CEventListIterator e; ! for(i = rEvents.begin(); i != e; i++) { ! CEvent* pEvent = *i; ! if(pEvent) { ! operator()(*pEvent); ! } else { ! break; ! } ! } } + /*! + Function Call operator. This function call operator processes a single event. + Processing is simple, + - Check the filter condition (CheckCondition). + - If the filter condition is true, format the output event (FormatOutputEvent). ! \note For this ABC, CheckCondition is pure virtual. There is, however ! a concept of a default output event format, which is implemented by our ! FormatOutputEvent member function. ! ! \param rEvent (in): ! Reference to the event to process. ! */ ! void ! CEventFilter::operator()(CEvent& rEvent) ! { ! if(CheckCondition(rEvent)) { ! FormatOutputEvent(rEvent); ! } } + /*! + Format the description of an event. This overridable interacts with + the output event stream and produces the event description record. + The event Description record describes the contents of events in the output + file. This record can be used to drive a general purpose unpacker for + filtered data. + Note that we can only format the information for parameters that exist. + The format of a header is the following: ! \verbatim ! +---------------------+ ! | "header" | ! +---------------------+ ! | NumParams | ! +---------------------+ ! | Name string(1) | ! +---------------------+ ! | ... | ! +---------------------+ ! |Name string(NumParams| ! +---------------------+ ! \endverbatim ! */ ! void ! CEventFilter::FormatEventDescription() ! { ! if(!m_pOutputEventStream) return; // No stream so give up. ! vector<string> Names = IdsToNames(); // Get names for ids that exist. ! *m_pOutputEventStream << headerlabel; // Indicate this is a header. ! *m_pOutputEventStream << (Names.size()); ! for(int i =0; i < Names.size(); i++) { ! *m_pOutputEventStream << (Names[i]); // The name to match with inbound. ! } } + /*! + Format an event into the output stream. This overridable interacts with the + output event stream and produces an event record. The Event record + contains a single event. It has the following format: ! \verbatim ! +-------------------------+ ! | "event" | ! +-------------------------+ ! |NumParams bits of bitmask| ! +-------------------------+ ! |Param for lowest setbit | ! +-------------------------+ ! | ... | ! +-------------------------+ ! |Param for highest setbit | ! +-------------------------+ ! ! \endverbatim ! ! \param rEvent (in): ! Reference to the event to output. ! */ ! void ! CEventFilter::FormatOutputEvent(CEvent& rEvent) ! { ! if(!m_pOutputEventStream) return; ! ! int nParams = m_vParameterIds.size(); ! int nBitmaskwords = ((nParams + sizeof(unsigned) - 1) / sizeof(unsigned)); ! unsigned Bitmask[nBitmaskwords]; ! ! for(int i = 0; i < nBitmaskwords; i++) { ! Bitmask[i] = 0; ! } ! ! // Figure out the bit mask: A bit is set for each valid parameter: ! ! int nValid = 0; ! for(int i =0; i < nParams; i++) { ! if(rEvent[m_vParameterIds[i]].isValid()) { ! setBit(Bitmask, i); ! nValid++; ! } ! } ! // Declare required freespace to allow the output stream to close: ! // the buffer if this event doesn't fit. ! ! size_t intsize = m_pOutputEventStream->sizeofInt(); ! size_t floatsize = m_pOutputEventStream->sizeofFloat(); ! size_t hdrsize = m_pOutputEventStream->sizeofString(eventlabel); ! ! ! m_pOutputEventStream->Require(nBitmaskwords*intsize + ! nValid*floatsize + ! hdrsize); ! ! // Write the header: ! ! *m_pOutputEventStream << (eventlabel); ! ! // Write the bitmask: ! ! for(int i =0; i < nBitmaskwords; i++) { ! *m_pOutputEventStream << Bitmask; ! } ! ! // Write the valid parameters: ! ! for(int i =0; i < nParams; i++) { ! if(rEvent[m_vParameterIds[i]].isValid()) { ! *m_pOutputEventStream << rEvent[m_vParameterIds[i]]; ! } ! } } + /*! + Return the default name of a filter file. This is ~/filter.flt + Since we are not a shell, ~ must be obtained by translating HOME + if HOME doesn't translate, we use . instead. ! \return string containing the default filename. ! */ ! string ! CEventFilter::DefaultFilterFilename() ! { ! string Filename; ! char* pHome = getenv("HOME"); ! if(pHome) { ! Filename = pHome; ! } else { ! Filename = "."; ! } ! Filename += "/filter.flt"; ! return Filename; } + /*! + Translates parameter names to parameter ids. + - Clear the m_vParameterIds member. + - For each parameter in m_vParameterNames that is valid, add it's id to + m_vParameterIds. Validity means in this case that a parameter by this + name exists in the histogrammer's parameter dictionary. + */ + void + CEventFilter::NamesToIds() + { + CHistogrammer* pHistogrammer = (CHistogrammer*)gpEventSink; + if(!m_vParameterIds.empty()) m_vParameterIds.clear(); + + int nParams = m_vParameterNames.size(); + for(int i = 0; i < nParams; i++) { + CParameter* pParam = pHistogrammer->FindParameter(m_vParameterNames[i]); + if(pParam) { + m_vParameterIds.push_back(pParam->getNumber()); + } + } + } + /*! + Returns a string of parameter names that corresponds to the set of + parameter ids in m_vParameterIds this is not the same as m_vParameterNames + as that vector is allowed to have elements that are deleted parameters. + Note that it is an error for the backward translation to fail, and this + results in an exception. ! \return vector<string> ! The vector of parameter names corresponding to the ! ids in the m_vParameterIds member. ! ! \throw CDictionaryException which will have the reasdon knNoSuchid. ! ! */ ! vector<string> ! CEventFilter::IdsToNames() throw (CDictionaryException) ! { ! CHistogrammer* pHistogrammer = (CHistogrammer*)gpEventSink; ! vector<string> names; ! for(int i = 0; i < m_vParameterIds.size(); i++) { ! CParameter* pParam = pHistogrammer->FindParameter(m_vParameterIds[i]); ! if(!pParam) { ! throw CDictionaryException(CDictionaryException::knNoSuchId, ! "CEventFilter::IdsToNames id -> name xlation", ! "-unknown-"); ! } ! names.push_back(pParam->getName()); ! } ! ! return names; ! } ! /*! ! Set a bit in a bit vector. The bit is assumed to fit in the vector. ! */ ! inline void ! CEventFilter::setBit(unsigned* bits, unsigned offset) ! { ! int element = offset/sizeof(unsigned); ! int mask = 1 << (offset % sizeof(unsigned)); ! bits[element] |= mask; ! } ! /*! ! Set the parameter names: ! - Replace the vector m_vParameterNames ! Note that this only takes effect when the filter is enabled ! next time. ! \param names (const vector<string>& in): ! Set of parameter names. ! */ ! void ! CEventFilter::setParameterNames(const vector<string>& rNames) ! { ! m_vParameterNames = rNames; } Index: EventFilter.h =================================================================== RCS file: /cvsroot/nsclspectcl/SpecTcl/Filter/EventFilter.h,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** EventFilter.h 20 Jul 2003 00:14:52 -0000 1.7 --- EventFilter.h 16 Sep 2003 11:49:12 -0000 1.8 *************** *** 7,69 **** #define __EVENTFILTER_H ! #ifndef __STL_STRING ! #include <string> ! #define __STL_STRING #endif ! #ifndef __EVENT_H ! #include <Event.h> ! #define __EVENT_H #endif ! #ifndef __EVENTLIST_H ! #include <EventList.h> ! #define __EVENTLIST_H #endif - #ifndef __EVENTSINK_H - #include <EventSink.h> - #define __EVENTSINK_H - #endif ! #ifndef __OUTPUTEVENTSTREAM_H ! #include <OutputEventStream.h> ! #define __OUTPUTEVENTSTREAM_H #endif // Class. class CEventFilter : public CEventSink { ! // Attributes. ! protected: ! Bool_t m_fEnabled; ! string m_sFileName; ! vector<string> m_vParameterNames; ! COutputEventStream* m_pOutputEventStream; public: ! // Constructors. CEventFilter(); CEventFilter(string& rFileName); - //CEventFilter(COutputEventStream&); // I doubt that this will ever be used, even if it at all could be. virtual ~CEventFilter(); ! // Operators. ! virtual void operator()(CEventList&) = 0; // If flag is set, call event formatter. ! virtual void operator()(CEvent&) = 0; // If flag is set, call event formatter. ! CEventFilter& operator=(const CEventFilter&); ! // Additional functions. ! void Enable(); ! void Disable(); ! string ParseFileName(string&); ! void setFileName(string&); ! string getFileName(); ! COutputEventStream& AttachOutputEventStream(COutputEventStream&); ! COutputEventStream& DetachOutputEventStream(); ! virtual void FormatOutputEvent(CEvent&); //protected: ! Bool_t CheckEnabled(); ! virtual Bool_t CheckCondition(CEvent&); ! }; // CEventFilter. #endif --- 7,125 ---- #define __EVENTFILTER_H ! #ifndef __EVENTSINK_H ! #include <EventSink.h> ! #define __EVENTSINK_H #endif ! #ifndef __HISTOTYPES_H ! #include <histotypes.h> #endif ! #ifndef __STL_VECTOR ! #include <vector> ! #define __STL_VECTOR #endif ! #ifndef __STL_STRING ! #include <string> ! #define __STL_STRING #endif + // forward definitions: + + class CEvent; + class CEventList; + class CXdrOutputStream; + class CDictionaryException; + // Class. + /*! + Abstract base class for event filters. An event filter is an event sink + that produces an output stream that is a subset of the input event stream. + The subsetting has two selections + + - Events - Only events that satisfy a gate are output on the output stream. + - Parameters - Only the specified subset of parameters are output on the + output stream. + + */ class CEventFilter : public CEventSink { ! ! // Attributes. ! ! protected: ! Bool_t m_fEnabled; //!< Filter only works when enabled. ! string m_sFileName; //!< Name of output file. ! vector<string> m_vParameterNames; //!< Names of parameters in output. ! vector<UInt_t> m_vParameterIds; //!< Ids of params in output stream. ! CXdrOutputStream* m_pOutputEventStream; //!< Output file. public: ! // Constructors and other canonical operations. ! CEventFilter(); CEventFilter(string& rFileName); virtual ~CEventFilter(); ! // Copies etc. are not allowed: ! ! private: ! CEventFilter& operator=(const CEventFilter&); ! CEventFilter(const CEventFilter& rhs); ! int operator==(const CEventFilter& rhs); ! int operator!=(const CEventFilter& rhs); ! public: ! // Selectors. ! public: ! ! vector<string> getParameterNames() const { ! return m_vParameterNames; ! } ! vector<UInt_t> getParameterIds() const { ! return m_vParameterIds; ! } ! Bool_t CheckEnabled() const { ! return m_fEnabled; ! } ! string getFileName() const { ! return m_sFileName; ! } ! CXdrOutputStream* getOutputStream() { // not const. ! return m_pOutputEventStream; ! } ! // Mutators. ! protected: ! // Operations on the class. ! public: ! ! void setParameterNames(const vector<string>& names); ! void setOutputStream(CXdrOutputStream* str); ! ! void Enable(); //!< Enable the filter. ! void Disable(); //!< Disable the filter. ! void setFileName(string&); //!< Choose a new filename. ! ! ! virtual void operator()(CEventList& rEvents); //!< Process list of events. ! virtual void operator()(CEvent& rEvent); //!< Process single event. //protected: ! protected: ! // Behavioral override hooks. ! ! virtual Bool_t CheckCondition(CEvent& rEvent) = 0; ! virtual void FormatEventDescription(); //!< Describe event in output file ! virtual void FormatOutputEvent(CEvent& rEvent); //!< Format a filtered event ! ! // utilities: ! ! static string DefaultFilterFilename(); //!< Return default filter filename. ! void NamesToIds(); //!< Translate param names -> ids. ! vector<string> IdsToNames() ! throw (CDictionaryException); //!< and back again. ! static void setBit(unsigned* bits, unsigned offset); //!< set a bit. ! }; ! #endif |