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 13103 2010-03-31 02:24:47Z 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->itsSource == 0) LFATAL("Received event [%s] with invalid source", e->toString().c_str()); 00390 SimEventQueue::RealmData *rd = getRealm(e->itsSource->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->itsSource == e->itsSource && 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->itsSource == eventsrc) { 00440 // run the callback function: 00441 LDEBUG("CALLBACK[%.2fms]: [%s]:%s, EVENT=[%s]", now().msecs(), e->itsSource->realm().c_str(), 00442 (*ii)->toString().c_str(), ebase->toString().c_str()); 00443 00444 (*ii)->execute(*this, ebase); 00445 00446 // this event has been "consumed" by that caller, make a note of 00447 // that if caller was a full-blown SimModule: 00448 if (caller != 0 && (flags & SEQ_MARK)) e->markDone(caller); 00449 } 00450 ++ii; 00451 } 00452 } 00453 00454 // let our helper know what happened: 00455 postHelper(typeid(E), e); 00456 } 00457 00458 // ###################################################################### 00459 template <class R> inline 00460 size_t SimEventQueue::request(rutz::shared_ptr<R> r, const SimReqQueueFlag flags) 00461 { 00462 // reject uninitialized shared_ptr's: 00463 if (r.is_valid() == false) LFATAL("You cannot request invalid SimReqs."); 00464 00465 // enforce that R should derive from SimReq, i.e., a pointer to an object of type R should be dyn_cast'able to a 00466 // pointer to type SimReq: 00467 rutz::shared_ptr<SimReq> rbase; dyn_cast_to_from(rbase, r); 00468 if (rbase.is_valid() == false) 00469 LFATAL("Passed request of type '%s' does not derive from SimReq", rutz::demangled_name(typeid(*r))); 00470 00471 // plunge into the appropriate realm: 00472 if (r->itsSource == 0) LFATAL("Received req [%s] with invalid source", r->toString().c_str()); 00473 SimEventQueue::RealmData *rd = getRealm(r->itsSource->realm(), false); 00474 srhm *rhmap = &(rd->reqhandlers); 00475 00476 // Call all our registered handlers: 00477 size_t donesofar = 0; 00478 srhm::iterator i = rhmap->find(&typeid(R)); 00479 if (i != rhmap->end()) 00480 { 00481 // we have handlers for this request type: 00482 rutz::shared_ptr<ssrhb> rhset = i->second; 00483 00484 // call them all in order: 00485 ssrhb::iterator ii = rhset->begin(), stop = rhset->end(); 00486 00487 while (ii != stop) { 00488 // Handle the request: 00489 const SimModule *reqsrc = (*ii)->reqsrc(); 00490 00491 // Only consider it if either we con't care about a specific req source, or we do care and the source matches: 00492 if (reqsrc == 0 || r->itsSource == reqsrc) { 00493 00494 // run the handler function: 00495 LDEBUG("HANDLER[%.2fms]: [%s]:%s, REQ=[%s]", now().msecs(), r->itsSource->realm().c_str(), 00496 (*ii)->toString().c_str(), rbase->toString().c_str()); 00497 00498 (*ii)->execute(*this, rbase); 00499 ++ donesofar; 00500 00501 // do we want to enforce unique handling? 00502 if (donesofar > 1 && (flags & SRQ_SEVERAL_FATAL)) 00503 LFATAL("More than one handler for %s requested by %s", 00504 r->toString().c_str(), r->itsSource->tagName().c_str()); 00505 } 00506 ++ii; 00507 } 00508 } 00509 00510 00511 if (donesofar == 0 && (flags & SRQ_NONE_FATAL)) 00512 LFATAL("No handler for %s requested by %s", r->toString().c_str(), r->itsSource->tagName().c_str()); 00513 00514 // let our helper know what happened: 00515 requestHelper(typeid(R), r); 00516 00517 return donesofar; 00518 } 00519 00520 // ###################################################################### 00521 template <class E> inline 00522 SeC<E> SimEventQueue::check(const SimModule* caller, 00523 const SimEventQueueFlag flags, 00524 const SimModule* eventsrc) 00525 { 00526 // plunge into the appropriate realm: 00527 if (caller == 0) LFATAL("Received check request for [%s] from invalid caller", rutz::demangled_name(typeid(E))); 00528 SimEventQueue::RealmData *rd = getRealm(caller->realm(), false); 00529 SeqEntryVec *sevec = &(rd->events); 00530 00531 SeqEntryVec::iterator e = sevec->begin(); 00532 rutz::shared_ptr<E> event; 00533 00534 while(e != sevec->end()) { 00535 // Only consider if either we con't care about a specific event source, or we do care and the source matches: 00536 if (eventsrc == 0 || e->second->itsSource == eventsrc) { 00537 // attempt a dynamic cast to type E: 00538 rutz::shared_ptr<E> ev = rutz::dyn_cast<E>(e->second); 00539 00540 // if the dynamic cast succeeded, this event has the type we are looking for: 00541 if (ev.is_valid()) { 00542 // do we want to skip this event (if already marked, unless we don't care about marking)? 00543 if ((flags & SEQ_UNMARKED) == 0 || ev->isDone(caller) == false) { 00544 // ok, we want to consider this event as a match. Done searching. 00545 event = ev; 00546 break; 00547 } 00548 } 00549 } 00550 // keep searching... 00551 ++e; 00552 } 00553 00554 // mark event as done if desired: 00555 if (event.is_valid() && (flags & SEQ_MARK)) event->markDone(caller); 00556 00557 // let our helper know what happened: 00558 checkHelper(typeid(E), event, caller, flags, eventsrc); 00559 00560 // if could not find a match, event is an empty shared_ptr: 00561 return SeC<E>(event); 00562 } 00563 00564 // ###################################################################### 00565 inline void 00566 SimEventQueue::checkHelper(const std::type_info& ename, 00567 const rutz::shared_ptr<SimEvent>& e, 00568 const SimModule* caller, 00569 const SimEventQueueFlag flags, 00570 const SimModule* eventsrc) 00571 { } 00572 00573 // ###################################################################### 00574 inline void 00575 SimEventQueue::postHelper(const std::type_info& etype, const rutz::shared_ptr<SimEvent>& e) 00576 { } 00577 00578 // ###################################################################### 00579 inline void 00580 SimEventQueue::requestHelper(const std::type_info& rtype, const rutz::shared_ptr<SimReq>& r) 00581 { } 00582 00583 // ###################################################################### 00584 template <class T> 00585 inline SeC<T>::SeC(const rutz::shared_ptr<T> event) throw() : 00586 itsEvent(event) 00587 { } 00588 00589 template <class T> 00590 inline SeC<T>::SeC(const SeC<T>& other) throw() : 00591 itsEvent(other.itsEvent) 00592 { } 00593 00594 template <class T> inline 00595 SeC<T>::~SeC() 00596 { } 00597 00598 template <class T> inline 00599 T* SeC<T>::operator->() const throw() 00600 { return itsEvent.get(); } 00601 00602 template <class T> inline 00603 T& SeC<T>::operator*() const throw() 00604 { return *(itsEvent.get()); } 00605 00606 template <class T> inline 00607 SeC<T>::operator bool() const 00608 { return itsEvent.is_valid(); } 00609 00610 template <class T> inline 00611 bool SeC<T>::is_valid() const 00612 { return itsEvent.is_valid(); } 00613 00614 template <class T> inline 00615 rutz::shared_ptr<T>& SeC<T>::getPtr() 00616 { return itsEvent; } 00617 00618 template <class T> inline 00619 const rutz::shared_ptr<T>& SeC<T>::getPtr() const 00620 { return itsEvent; } 00621 00622 00623 // ###################################################################### 00624 /* So things look consistent in everyone's emacs... */ 00625 /* Local Variables: */ 00626 /* mode: c++ */ 00627 /* indent-tabs-mode: nil */ 00628 /* End: */ 00629 00630 #endif // SIMULATION_SIMEVENTQUEUE_H_DEFINED