Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

SimEventQueue.H

Go to the documentation of this file.
00001 /*!@file Simulation/SimEventQueue.H Dispatch simulation events */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Simulation/SimEventQueue.H $
00035 // $Id: SimEventQueue.H 11082 2009-04-02 23:31:50Z itti $
00036 //
00037 
00038 #ifndef SIMULATION_SIMEVENTQUEUE_H_DEFINED
00039 #define SIMULATION_SIMEVENTQUEUE_H_DEFINED
00040 
00041 #include "Component/ModelParam.H"
00042 #include "Simulation/SimEvent.H"
00043 #include "Simulation/SimModule.H"
00044 #include "Simulation/SimCallback.H"
00045 #include "Simulation/SimCallbackClient.H"
00046 #include "Simulation/SimReq.H"
00047 #include "Simulation/SimReqHandler.H"
00048 #include "Simulation/SimReqHandlerClient.H"
00049 #include "Simulation/SimEventQueueFlag.H"
00050 #include "Util/SimTime.H"
00051 #include "rutz/demangle.h"
00052 #include <vector>
00053 #include <map>
00054 #include <set>
00055 
00056 //! Simple enum to return a status after evolve()
00057 enum SimStatus
00058   {
00059     SIM_CONTINUE,
00060     SIM_BREAK
00061   };
00062 
00063 //! Helper class to check for events (defined below)
00064 template <class T> class SeC;
00065 
00066 //! Helper class to gather events generated while running a simulation
00067 /*! The class maintains a list of events which may arise from various
00068   simulation modules, and can be queried for specific events.
00069 
00070   This class implements a so-called 'blackboard architecture', a
00071   concept which was introduced in artificial intelligence research to
00072   facilitate information sharing among multiple heterogeneous
00073   problem-solving agents. The basic idea is that the blackboard is a
00074   shared repository of information which all agents can access while
00075   working towards the solution to a given problem.
00076 
00077   Because different modules are usually run sequentially, e.g., in
00078   Brain::evolve(), the intent here is that we keep track of both the
00079   events that arise during a given evolve at SimTime t and during the
00080   previous evolve. If an event arises after a given module has already
00081   been evolve'd for the current iteration, that module will know about
00082   the event on the next iteration. For example, in Brain::evolve(), we
00083   evolve the SaliencyMap module before the EyeHeadController module;
00084   hence if an eye saccade is initiated by the EyeHeadController, the
00085   SaliencyMap will become aware of that at the next iteration, and may
00086   decide to take appropriate action, e.g., saccadic suppression. To
00087   eliminate events older than a given time, use prune(), typically
00088   this would be done at the beginning of Brain::evolve().
00089 
00090   IMPORTANT: When a given SimModule posts an event at time t, all
00091   events posted by that same SimModule at times < t are erased from
00092   the queue. This is as soon as the event type matches, whether or not
00093   the event's contents match.
00094 
00095   HISTORICAL NOTE: SimEventQueue was introduced as an attempt to give
00096   more autonomy to the Brain modules by employing a blackboard
00097   architecture. An example of how things worked before is as follows:
00098   a SaccadeController may decide in its evolve() function that it is
00099   time to blink, and will switch itself to blink state.
00100   Brain::evolve() would have to query the controller after running
00101   evolve() on it, to check whether anything happened, like for example
00102   the start of the blink. If so, Brain::eyeBlink() would be triggered,
00103   which in turn would dispatch the event to several other modules,
00104   calling for example SimulationViewer::eyeBlink() and
00105   SaliencyMap::blinkSuppression(). The more types of events could
00106   occur, the more complex Brain::evolve() was becoming. With
00107   SimEventQueue, most of the complex orchestration which was in
00108   Brain::evolve() is now delegated to the brain modules
00109   themselves. For example, when SaccadeController initiates a blink,
00110   it simply posts a SimEvent indicating so. When SimulationViewer's
00111   turn comes to evolve, it can query SimEventQueue to check whether a
00112   blink has started, and take appropriate action. */
00113 class SimEventQueue : public SimModule {
00114 public:
00115   //! Constructor
00116   /*! An optional start time for the master simulation clock may be
00117     provided. */
00118   SimEventQueue(OptionManager& mgr,
00119                 const std::string& descrName = "Simulation Event Queue",
00120                 const std::string& tagName = "SimEventQueue",
00121                 const SimTime starttime = SimTime::ZERO());
00122 
00123   //! Destructor
00124   virtual ~SimEventQueue();
00125 
00126   //! Post a new SimEvent; typically, SimModule modules do this
00127   template <class E> inline
00128   void post(rutz::shared_ptr<E> e);
00129 
00130   //! Handle a new SimReq; typically, SimModule modules do this
00131   /*! Note two differences between this and post(): here, the SimReq
00132       object does not end up in the queue, it is just privately passed
00133       to the event handlewr, who will modify it, and then the caller
00134       can use the results. Second, SimReq objects are typically passed
00135       read/write while SimEvent objects are read-only in post(). This
00136       function returns the number of handlers that were triggered by
00137       the request. Zero means that nobody caught the request. Default
00138       behavior is to throw a fatal exception if zero or more than 1
00139       handlers catch the request. */
00140   template <class R> inline
00141   size_t request(rutz::shared_ptr<R> r,
00142                const SimReqQueueFlag flags = SRQ_NONE_FATAL | SRQ_SEVERAL_FATAL);
00143 
00144   //! Return event, if any, that satisfies the given criteria
00145   /*! Example usage is as follows:
00146     \code
00147 
00148     // Assume a SimEventQueue object q
00149     // Assume that caller is a SimModule
00150     // Assume that CovertShift derives from SimEvent
00151     if (SeC<CovertShift> e = q.check<CovertShift>(this))
00152       {
00153         // handle the event; you can use 'e' pretty much as you
00154         // would use a shared_ptr
00155       }
00156 
00157     \endcode
00158 
00159     You can specify an eventsrc SimModule to further narrow the search
00160     to only events that originated from this module. NOTE: only events
00161     which are either public or intended for the caller will be
00162     returned (assuming that all other match criteria are also
00163     fullfilled). See Simulation/SimEvent.H for the distinction between
00164     public and private events. By default, the flags are set so that
00165     we will return the most recent matching unmarked event, then mark
00166     it in the queue as done by the caller module; hence several calls
00167     to check will return all unmarked events (from most recent to
00168     oldest) until they have all been marked.  PROGRAMMER NOTE: don't
00169     overload this, instead you can overload checkHelper() which is
00170     called from here. */
00171   template <class E> inline
00172   SeC<E> check(const SimModule* caller,
00173                const SimEventQueueFlag flags = SEQ_UNMARKED | SEQ_MARK,
00174                const SimModule* eventsrc = 0);
00175 
00176   //! Increment the master clock and delete old events
00177   /*! Events whose time is < t just before we increment the clock will
00178     be removed from the queue. We will here also check for some events
00179     that are handled directly by the queue agent. */
00180   virtual SimStatus evolve();
00181 
00182   //! Get the master clock's time
00183   virtual const SimTime& now() const;
00184 
00185   //! Erase the entire queue; like reset() but does not reset time
00186   /*! Use reset() instead unless you know what you are doing. */
00187   virtual void clear();
00188 
00189   //! Erase all events with time <= tt
00190   virtual void prune(const SimTime& tt);
00191 
00192   //! Reset the time to the given value and erase the entire queue
00193   /*! Like reset() but does not propagate to subcomponents.  Use
00194    reset() instead unless you know what you are doing. */
00195   virtual void resetTime(const SimTime& tim = SimTime::ZERO());
00196 
00197   //! Register a new SimCallbackClient, taking all its callbacks
00198   void registerSimCallbackClient(SimModule *s);
00199 
00200   //! Register a new SimReqHandlerClient, taking all its callbacks
00201   void registerSimReqHandlerClient(SimModule *s);
00202 
00203   //! Show all registered callbacks
00204   void printCallbacks() const;
00205 
00206 protected:
00207   //! Simulation time step, in seconds
00208   OModelParam<SimTime> itsTimeStep;
00209 
00210   //! Exit after a given time in seconds (if not zero)
00211   OModelParam<SimTime> itsTooMuchTime;
00212 
00213   //! Display memory stats when a module posts a SimEventShowMemStats
00214   OModelParam<bool> itsShowMemStats;
00215 
00216   //! Default units for memory stats
00217   OModelParam<size_t> itsShowMemStatsUnits;
00218 
00219   //! text log file name
00220   OModelParam<std::string> itsLogFile;
00221 
00222   SimTime t;  //!< the simulation's master clock
00223 
00224   //! This is called by post(). Default is a no-op.
00225   /*! @param etype typeid of the event which the caller
00226     wanted to check for (use rutz::demangle(etype) to get the type name)
00227     @param e the event posted
00228     @param the post time */
00229   inline virtual
00230   void postHelper(const std::type_info& etype,
00231                   const rutz::shared_ptr<SimEvent>& e);
00232 
00233   //! This is called by request(). Default is a no-op.
00234   inline virtual
00235   void requestHelper(const std::type_info& etype,
00236                      const rutz::shared_ptr<SimReq>& e);
00237 
00238   //! this is called by check(). Default is a no-op.
00239   /*! @param etype typeid of the event which the caller
00240     wanted to check for (use rutz::demangle(etype) to get the type name)
00241     @param e matching event found, will be invalid if no match was
00242     found. Note that e may have a different type from what the caller
00243     was looking for, namely it could be a derived class from the one
00244     looked for.
00245     @param caller the SimModule that called check().
00246     @param flags the flags passed to check().
00247     @param eventsrc the event source passed to check() if any.  */
00248   inline virtual
00249   void checkHelper(const std::type_info& etype,
00250                    const rutz::shared_ptr<SimEvent>& e,
00251                    const SimModule* caller,
00252                    const SimEventQueueFlag flags,
00253                    const SimModule* eventsrc);
00254 
00255   //! Reset and propagate the reset signal to the sub-components
00256   /*! See the base function in ModelComponent.H for info. */
00257   virtual void reset1();
00258 
00259   //! get started
00260   virtual void start1();
00261 
00262   struct TypeInfoCompare {
00263     bool operator()(const std::type_info* t1, const std::type_info* t2) const
00264     { return (t1->before(*t2)); }
00265   };
00266 
00267   // our queue of SimEvents is segmented into realms by using a map
00268   // with the realm name as key; for each realm, we have events,
00269   // callbacks, and request handlers:
00270 
00271   // Data for events: within each realm, we simply pile them up into a
00272   // vector and keep track of their time:
00273   typedef std::pair<SimTime, rutz::shared_ptr<SimEvent> > SeqEntry;
00274   typedef std::vector<SeqEntry> SeqEntryVec;
00275 
00276   // Data for callback management:
00277   // sscbb is a multiset type where we just pile up all the callbacks
00278   //   for a given event type (in the given realm), using some ordering by
00279   //   priority and insertion order.
00280   // scbm is a map of sscbb where each entry corresponds to a given event
00281   //   type (in the current realm)
00282   typedef std::multiset<SimCallbackBase*, SimCallbackCompare> sscbb;
00283   typedef std::map<const std::type_info*, rutz::shared_ptr<sscbb>, TypeInfoCompare> scbm;
00284 
00285   // Data for SimReq handler management:
00286   typedef std::vector<SimReqHandlerBase*> ssrhb;
00287   typedef std::map<const std::type_info*, rutz::shared_ptr<ssrhb>, TypeInfoCompare> srhm;
00288 
00289   // we have one of these for each realm:
00290   typedef struct {
00291     SeqEntryVec events;
00292     scbm callbacks;
00293     srhm reqhandlers;
00294   } RealmData;
00295 
00296   typedef std::map<std::string, RealmData> SeqData;
00297   SeqData itsQueue;
00298 
00299   // get access to the RealmData for a given realm; if create_on_fail
00300   // is true, a new realm will be created if one was not found by that
00301   // name; otherwise a fatal error will occur if realm not found:
00302   RealmData* getRealm(const std::string& realmname, const bool create_on_fail);
00303 
00304 private:
00305   // prevent people from calling SimModule::evolve() on us:
00306   virtual void evolve(SimEventQueue& q);
00307 
00308   // show memory stats
00309   void showMemStats(const int frame, const size_t units) const;
00310 };
00311 
00312 // ######################################################################
00313 //! SeC class to assist with checking for events
00314 /*! This class is to allow for a simple syntax when checking for
00315   events:
00316   <PRE>
00317 
00318   // assume a SimEventQueue q
00319   if (SeC<SimEventBreak> e = q.check<SimEventBreak>(this))
00320     {
00321       // a matching event was found and is in 'e'
00322       cerr<<"Break: "<<e->toString()<<endl;
00323     }
00324 
00325   </PRE>
00326 
00327   With this syntax, matching event 'e' will only live within the scope
00328   of the 'if' statement. Note that this is a somewhat weird syntax and
00329   other seemingly equivalent syntaxes do not work. There must be an
00330   assignment and a provision to convert to bool for this to work. */
00331 template <class T>
00332 class SeC {
00333 public:
00334   // Constructor; used by SimEventQueue::check()
00335   inline SeC(const rutz::shared_ptr<T> event) throw();
00336 
00337   // Assignment constructor
00338   inline SeC(const SeC<T>& other) throw();
00339 
00340   //! Destructor
00341   inline virtual ~SeC();
00342 
00343   //! Get the underlying event
00344   inline T* operator->() const throw();
00345 
00346   //! Get the underlying event
00347   inline T& operator*() const throw();
00348 
00349   //! Convert to bool by checking whether underlying event is valid
00350   /*! This is the key to enabling declaration of a SeC variable inside
00351     an if(...) statement. */
00352   inline operator bool() const;
00353 
00354   //! Check whether the pointee is non-null (there is an event)
00355   inline bool is_valid() const;
00356 
00357   //! Get the underlying shared_ptr
00358   inline rutz::shared_ptr<T>& getPtr();
00359 
00360   //! Get the underlying shared_ptr, const version
00361   inline const rutz::shared_ptr<T>& getPtr() const;
00362 
00363 private:
00364   rutz::shared_ptr<T> itsEvent;
00365 
00366   // forbidden
00367   inline SeC() { };
00368 };
00369 
00370 // ######################################################################
00371 // inlined functions:
00372 // ######################################################################
00373 
00374 // ######################################################################
00375 template <class E> inline
00376 void SimEventQueue::post(rutz::shared_ptr<E> e)
00377 {
00378   // reject uninitialized shared_ptr's:
00379   if (e.is_valid() == false) LFATAL("You cannot post invalid events.");
00380 
00381   // enforce that E should derive from SimEvent, i.e., a pointer to an
00382   // object of type E should be dyn_cast'able to a pointer to type
00383   // SimEvent:
00384   rutz::shared_ptr<SimEvent> ebase; dyn_cast_to_from(ebase, e);
00385   if (ebase.is_valid() == false)
00386     LFATAL("Passed event of type '%s' does not derive from SimEvent", rutz::demangled_name(typeid(*e)));
00387 
00388   // plunge into the appropriate realm:
00389   if (e->source() == 0) LFATAL("Received event [%s] with invalid source", e->toString().c_str());
00390   SimEventQueue::RealmData *rd = getRealm(e->source()->realm(), false);
00391   SeqEntryVec *sevec = &(rd->events);
00392   scbm *cbmap = &(rd->callbacks);
00393 
00394   // let's delete all events from this caller that have same type as e and a time < t:
00395   SeqEntryVec::iterator ee = sevec->begin();
00396   while (ee != sevec->end())
00397     {
00398       rutz::shared_ptr<SimEvent> evt = ee->second;
00399 
00400       // is evt a shared_ptr onto a SimEvent derivative of type E,
00401       // coming from the same source as e, and with a time < tt?
00402       if (typeid(*evt) == typeid(*e) &&
00403           evt->source() == e->source() &&
00404           ee->first < t)
00405         ee = sevec->erase(ee);
00406       else ++ee;
00407     }
00408 
00409   // now push the new event into the queue, in case other people later
00410   // need it even though they don't have a callback registered for it
00411   // (they will have to manually do a check() for it), or in case some
00412   // of our callbacks below trigger other callbacks which in turn need
00413   // to check for our event::
00414   sevec->push_back(SeqEntry(t, e));
00415 
00416   // Call all our registered callbacks:
00417   scbm::iterator i = cbmap->find(&typeid(E));
00418   if (i != cbmap->end()) {
00419     // we have callbacks for this event type:
00420     rutz::shared_ptr<sscbb> cbset = i->second;
00421 
00422     // call them all in order (our sets are sorted):
00423     sscbb::iterator ii = cbset->begin(), stop = cbset->end();
00424 
00425     while (ii != stop) {
00426       // should we trigger the callback and how should we dispose of
00427       // the event? The logic here is similar to that in check() so
00428       // make sure both stay in sync if you modify one of them.
00429       // Differences include: the event here is brand new, just
00430       // posted, so clearly it is unmarked and nobody has seen it yet,
00431       // all clients will see it for the first time.
00432       const SimEventQueueFlag flags = (*ii)->sflags();
00433       const SimModule *eventsrc = (*ii)->eventsrc();
00434       SimCallbackClient *cli = (*ii)->client();
00435       SimModule *caller = dynamic_cast<SimModule*>(cli); // or 0 if caller not a SimModule
00436 
00437       // Only consider this event if either we con't care about a
00438       // specific event source, or we do care and the source matches:
00439       if (eventsrc == 0 || e->source() == eventsrc) {
00440         // is there a specific recipient in that event (private
00441         // event)? is it our caller? otherwise, just skip:
00442         if (e->recipient() == 0 || e->recipient() == caller) {
00443           // run the callback function:
00444           LDEBUG("CALLBACK[%.2fms]: [%s]:%s, EVENT=[%s]", now().msecs(), e->source()->realm().c_str(),
00445                  (*ii)->toString().c_str(), ebase->toString().c_str());
00446 
00447           (*ii)->execute(*this, ebase);
00448 
00449           // this event has been "consumed" by that caller, make a note of
00450           // that if caller was a full-blown SimModule:
00451           if (caller != 0 && (flags & SEQ_MARK)) e->markDone(caller);
00452         }
00453       }
00454       ++ii;
00455     }
00456   }
00457 
00458   // let our helper know what happened:
00459   postHelper(typeid(E), e);
00460 }
00461 
00462 // ######################################################################
00463 template <class R> inline
00464 size_t SimEventQueue::request(rutz::shared_ptr<R> r, const SimReqQueueFlag flags)
00465 {
00466   // reject uninitialized shared_ptr's:
00467   if (r.is_valid() == false) LFATAL("You cannot request invalid SimReqs.");
00468 
00469   // enforce that R should derive from SimReq, i.e., a pointer to an
00470   // object of type R should be dyn_cast'able to a pointer to type
00471   // SimReq:
00472   rutz::shared_ptr<SimReq> rbase; dyn_cast_to_from(rbase, r);
00473   if (rbase.is_valid() == false)
00474     LFATAL("Passed request of type '%s' does not derive from SimReq", rutz::demangled_name(typeid(*r)));
00475 
00476   // plunge into the appropriate realm:
00477   if (r->source() == 0) LFATAL("Received req [%s] with invalid source", r->toString().c_str());
00478   SimEventQueue::RealmData *rd = getRealm(r->source()->realm(), false);
00479   srhm *rhmap = &(rd->reqhandlers);
00480 
00481   // Call all our registered handlers:
00482   size_t donesofar = 0;
00483   srhm::iterator i = rhmap->find(&typeid(R));
00484   if (i != rhmap->end())
00485     {
00486       // we have handlers for this request type:
00487       rutz::shared_ptr<ssrhb> rhset = i->second;
00488 
00489       // call them all in order:
00490       ssrhb::iterator ii = rhset->begin(), stop = rhset->end();
00491 
00492       while (ii != stop) {
00493         // Handle the request:
00494         const SimModule *reqsrc = (*ii)->reqsrc();
00495         SimReqHandlerClient *cli = (*ii)->client();
00496         SimModule *caller = dynamic_cast<SimModule*>(cli); // or 0 if caller not a SimModule
00497 
00498         // Only consider this req if either we con't care about a
00499         // specific req source, or we do care and the source matches:
00500         if (reqsrc == 0 || r->source() == reqsrc) {
00501           // is there a specific recipient in that req? is it our
00502           // caller? otherwise, just skip:
00503           if (r->recipient() == 0 || r->recipient() == caller) {
00504             // do we want to enforce unique handling?
00505             // run the handler function:
00506             LDEBUG("HANDLER[%.2fms]: [%s]:%s, REQ=[%s]", now().msecs(), r->source()->realm().c_str(),
00507                    (*ii)->toString().c_str(), rbase->toString().c_str());
00508 
00509             (*ii)->execute(*this, rbase);
00510             ++ donesofar;
00511 
00512             if (donesofar > 1 && (flags & SRQ_SEVERAL_FATAL))
00513               LFATAL("More than one handler for %s requested by %s [to %s]",
00514                      r->toString().c_str(),  r->source()->tagName().c_str(),
00515                      r->recipient() == 0 ? "Anyone" : r->recipient()->tagName().c_str());
00516           }
00517         }
00518         ++ii;
00519       }
00520     }
00521 
00522 
00523   if (donesofar == 0 && (flags & SRQ_NONE_FATAL))
00524     LFATAL("No handler for %s requested by %s [to %s]",
00525            r->toString().c_str(),  r->source()->tagName().c_str(),
00526            r->recipient() == 0 ? "Anyone" : r->recipient()->tagName().c_str());
00527 
00528   // let our helper know what happened:
00529   requestHelper(typeid(R), r);
00530 
00531   return donesofar;
00532 }
00533 
00534 // ######################################################################
00535 template <class E> inline
00536 SeC<E> SimEventQueue::check(const SimModule* caller,
00537                             const SimEventQueueFlag flags,
00538                             const SimModule* eventsrc)
00539 {
00540   // plunge into the appropriate realm:
00541   if (caller == 0) LFATAL("Received check request for [%s] from invalid caller", rutz::demangled_name(typeid(E)));
00542   SimEventQueue::RealmData *rd = getRealm(caller->realm(), false);
00543   SeqEntryVec *sevec = &(rd->events);
00544 
00545   SeqEntryVec::iterator e = sevec->begin();
00546   rutz::shared_ptr<E> event;
00547 
00548   while(e != sevec->end()) {
00549     // Only consider this event if either we con't care about a
00550     // specific event source, or we do care and the source matches:
00551     if (eventsrc == 0 || e->second->source() == eventsrc) {
00552       // attempt a dynamic cast to type E:
00553       rutz::shared_ptr<E> ev = rutz::dyn_cast<E>(e->second);
00554 
00555       // if the dynamic cast succeeded, this event has the type we
00556       // are looking for:
00557       if (ev.is_valid()) {
00558         // is there a specific recipient in that event (private
00559         // event)? is it our caller? otherwise, just skip:
00560         if (ev->recipient() == 0 || ev->recipient() == caller) {
00561           // do we want to skip this event (if already marked, unless
00562           // we don't care about marking)?
00563           if ((flags & SEQ_UNMARKED) == 0 || ev->isDone(caller) == false) {
00564             // ok, we want to consider this event as a match. Done searching.
00565             event = ev;
00566             break;
00567           }
00568         }
00569       }
00570     }
00571     // keep searching...
00572     ++e;
00573   }
00574 
00575   // mark event as done if desired:
00576   if (event.is_valid() && (flags & SEQ_MARK)) event->markDone(caller);
00577 
00578   // let our helper know what happened:
00579   checkHelper(typeid(E), event, caller, flags, eventsrc);
00580 
00581   // if could not find a match, event is an empty shared_ptr:
00582   return SeC<E>(event);
00583 }
00584 
00585 // ######################################################################
00586 inline void
00587 SimEventQueue::checkHelper(const std::type_info& ename,
00588                            const rutz::shared_ptr<SimEvent>& e,
00589                            const SimModule* caller,
00590                            const SimEventQueueFlag flags,
00591                            const SimModule* eventsrc)
00592 { }
00593 
00594 // ######################################################################
00595 inline void
00596 SimEventQueue::postHelper(const std::type_info& etype,
00597                           const rutz::shared_ptr<SimEvent>& e)
00598 { }
00599 
00600 // ######################################################################
00601 inline void
00602 SimEventQueue::requestHelper(const std::type_info& rtype,
00603                              const rutz::shared_ptr<SimReq>& r)
00604 { }
00605 
00606 // ######################################################################
00607 template <class T>
00608 inline SeC<T>::SeC(const rutz::shared_ptr<T> event) throw() :
00609   itsEvent(event)
00610 { }
00611 
00612 template <class T>
00613 inline SeC<T>::SeC(const SeC<T>& other) throw() :
00614   itsEvent(other.itsEvent)
00615 { }
00616 
00617 template <class T> inline
00618 SeC<T>::~SeC()
00619 { }
00620 
00621 template <class T> inline
00622 T* SeC<T>::operator->() const throw()
00623 { return itsEvent.get(); }
00624 
00625 template <class T> inline
00626 T& SeC<T>::operator*() const throw()
00627 { return *(itsEvent.get()); }
00628 
00629 template <class T> inline
00630 SeC<T>::operator bool() const
00631 { return itsEvent.is_valid(); }
00632 
00633 template <class T> inline
00634 bool SeC<T>::is_valid() const
00635 { return itsEvent.is_valid(); }
00636 
00637 template <class T> inline
00638 rutz::shared_ptr<T>& SeC<T>::getPtr()
00639 { return itsEvent; }
00640 
00641 template <class T> inline
00642 const rutz::shared_ptr<T>& SeC<T>::getPtr() const
00643 { return itsEvent; }
00644 
00645 
00646 // ######################################################################
00647 /* So things look consistent in everyone's emacs... */
00648 /* Local Variables: */
00649 /* mode: c++ */
00650 /* indent-tabs-mode: nil */
00651 /* End: */
00652 
00653 #endif // SIMULATION_SIMEVENTQUEUE_H_DEFINED

Generated on Sun Nov 22 13:43:11 2009 for iLab Neuromorphic Vision Toolkit by  doxygen 1.4.4