Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

EventRouter.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_EventRouter_h
00003 #define INCLUDED_EventRouter_h
00004 
00005 #include <vector>
00006 #include <queue>
00007 #include <map>
00008 #include <algorithm>
00009 #include "EventListener.h"
00010 #include "EventTrapper.h"
00011 #include "Shared/get_time.h"
00012 #include "Shared/debuget.h"
00013 #include "Shared/attributes.h"
00014 #include <iostream>
00015 
00016 //! This class will handle distribution of events as well as management of timers
00017 /*! Classes must inherit from EventListener and/or EventTrapper in order to
00018  *  receive events.
00019  *
00020  *  Use the global ::erouter instance of EventRouter to both send (post) and receive (subscribe/listen) to
00021  *  events.  (except if you are posting from within a MotionCommand, in
00022  *  which case you should use MotionCommand::postEvent() so that it can correctly
00023  *  handle inter-process communication issues under Aperios (the Aibo's OS) -- under a
00024  *  Unix-based OS, this wouldn't be necessary.)
00025  *
00026  *  The events available for processing are listed in EventBase::EventGeneratorID_t.
00027  *  Each generator ID's documentation specifies how to interpret the source ID field, and whether
00028  *  you can expect events with that generator ID to be of a subclass of EventBase,
00029  *  such as TextMsgEvent or LocomotionEvent.  Many generators send plain
00030  *  EventBase instances.
00031  *
00032  *  When multiple listeners are subscribed, the order in which an event is
00033  *  distributed among them is:
00034  *  -# "Specific" listeners: any listener which specifies a particular source id.
00035  *     (doesn't matter if they specified type id as well)
00036  *    - older listeners get events before more recently added listeners ("FIFO")
00037  *  -# "General" listeners: those that subscribe to an entire generator
00038  *    - older listeners get events before more recently added listeners ("FIFO")
00039  *
00040  *  ...but if you're relying on that ordering, there probably should be a cleaner
00041  *  way to do whatever you're doing.
00042  *
00043  *  TimerEvents are generally only sent to the generator which requested them.  So if 
00044  *  EventListener @e A requests a timer (see addTimer()) with ID 0 at two second intervals,
00045  *  and @e B requests a timer with ID 0 at three second intervals,
00046  *  each will still only receive the timers they requested - no cross talk.
00047  *  The timer generator is unique in this regard, which is why it is built in
00048  *  as an integral component of the EventRouter.  However, EventListener @e A
00049  *  <b>can</b> receive @e B's timers if it specifically wants to, via addListener().  See "Timers" below.
00050  *
00051  *  If an EventListener/EventTrapper subscribes to the same event source multiple
00052  *  times, it will receive multiple copies of the event.  However, the first call
00053  *  to removeListener for a source will remove all subscriptions to that source.\n
00054  *  Example: EventListener @e A subscribes to (buttonEGID,*,*), and twice to
00055  *  (buttonEGID,0,*).
00056  *    - If button 0 is pressed, @e A will get three copies of the event.
00057  *    - If button 1 is pressed, @e A will get one copy.
00058  *    - If removeListener(&A,buttonEGID) is called, the (buttonEGID,*,*) is
00059  *      removed, <em>as well as</em> both of (buttonEGID,0,*).
00060  *    - If removeListener(&A,buttonEGID,0) is called, both of (buttonEGID,0,*)
00061  *      are removed, but (buttonEGID,*,*) would be untouched.
00062  *
00063  *  <h3>Timers</h3>
00064  *  addTimer() allows you to request an TimerEvent to be sent at some later point in time,
00065  *  possibly on a repeating basis.  Timers are specific to the behavior which requests
00066  *  them, and you @e do @e not (and usually should not) call addListener() in order to receive a timer
00067  *  event.
00068  *
00069  *  There is an important different between addTimer() and #addListener(timerEGID,...)!
00070  *  addTimer will "create" the timer, and will send the timer to the listener
00071  *  which created it when the timer expires.  This means that as long as the listener in
00072  *  question does @e not call addListener(timerEGID), it will @e only receive its own timers.
00073  *  In other words, with this usage there is no confusion with timer cross-talk between
00074  *  listeners, because each listener is only receiving its own timers.
00075  *
00076  *  However, if a listener calls addListener(timerEGID), it will begin receiving @e all timer events
00077  *  from throughout the system.  This allows you to have one behavior "eavesdrop" on
00078  *  another's timers.  In order to determine which listener requested/created the timer,
00079  *  you can use the TimerEvent::getTarget() value.
00080  *
00081  *  So beware that if you call both addTimer() and addListener(foo,timerEGID), 'foo' will get
00082  *  two calls to processEvent() for its own timers, and one call for all other timers, and will
00083  *  have to know to call TimerEvent::getTarget() to distinguish its timers from other
00084  *  listener's timers (if it cares about the difference...)
00085  *
00086  *  Timers are sent to the requesting listener before being broadcast -- EventTrappers cannot
00087  *  filter a listener's own timers, but can prevent the timer from being broadcast to other listeners.
00088  *
00089  *  <h3>Event processing examples:</h3>
00090  *
00091  *  Posting events:
00092  *  @code
00093  *  //method A: basic event posting (EventBase instance is sent)
00094  *  erouter->postEvent(EventBase::aiEGID, 1234, EventBase::statusETID);
00095  *
00096  *  //method B: specific event instance is posted (have to use this style to post a subclass)
00097  *  TextMsgEvent txt("hello world");
00098  *  erouter->postEvent(txt);
00099  *  // or can be done in one line:
00100  *  erouter->postEvent(TextMsgEvent("hello world"))
00101  *  @endcode
00102  *
00103  *  Receiving events:
00104  *  @code
00105  *  //given an EventListener subclass:
00106  *  class YourListener : public EventListener {
00107  *  public:
00108  *    virtual void processEvent(const EventBase& e) {
00109  *      std::cout << "Got: " << e.getName() << std::endl;
00110  *    }
00111  *  };
00112  *
00113  *  YourListener yourList;
00114  *
00115  *  // subscribes it to all EventBase::aiEGID events:
00116  *  erouter->addListener(&yourList, EventBase::aiEGID);
00117  *
00118  *  // subscribes only to button activity from the head, but not other buttons:
00119  *  erouter->addListener(&yourList, EventBase::buttonEGID, ERS7Info::HeadButOffset);
00120  *  @endcode
00121  *  Typically in a BehaviorBase subclass, you would just specify 'this' instead of '&yourList'.
00122  *
00123  *  <h3>Timer processing examples:</h3>
00124  *
00125  *  Requesting/Creating timers:
00126  *  @code
00127  *  YourListener yourList; // (any EventListener subclass)
00128  *
00129  *  // sends a timer with source ID 123 every 5 seconds to yourList:
00130  *  erouter->addTimer(&yourList, 123, 5000);
00131  *
00132  *  // sends a timer with ID 456 after 1 second, *no repeat, one time only*
00133  *  erouter->addTimer(&yourList, 456, 1000, false);
00134  *
00135  *  // cancels the first timer
00136  *  erouter->removeTimer(&yourList, 123);
00137  *
00138  *  // postpone/update the second timer's settings (*doesn't* create two timers with the same ID)
00139  *  erouter->addTimer(&yourList, 456, 2500, false);
00140  *
00141  *  @endcode
00142  *  Again, typically in a BehaviorBase subclass, you would just specify 'this' instead of '&yourList'.
00143  *
00144  *  @see EventBase::EventGeneratorID_t for a complete listing of all generators,
00145  *  as well as instructions on how to add new generators.
00146  *  @see Tutorials:
00147  *    - <a href="../FirstBehavior2.html">Steps 3, 4, & 5 of Tekkotsu's First Behavior Tutorial</a>
00148  *    - <a href="http://www.cs.cmu.edu/~dst/Tekkotsu/Tutorial/events.shtml">David Touretzky's Events Chapter</a>
00149  *    - <a href="http://www.cs.cmu.edu/afs/cs/academic/class/15494-s06/www/lectures/behaviors.pdf">CMU's Cognitive Robotics course slides</a>
00150  */
00151 class EventRouter : public EventListener {
00152  public:
00153   EventRouter(); //!< Constructs the router
00154   virtual ~EventRouter() { reset(); removeAllTimers(); } //!< just calls reset and removeAllTimers()
00155   
00156   void reset() { listeners.clear(); trappers.clear(); removeAllTimers(); } //!< erases all listeners, trappers and timers, resets EventRouter
00157   
00158   
00159   //!@name Posting/Processing Events
00160   
00161   /*!@brief recommended to create and post an event using current buffer setting */
00162   void postEvent(EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid, unsigned int dur=0) { processEvent(EventBase(egid,sid,etid,dur)); }
00163   void postEvent(EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid, unsigned int dur, const std::string& n, float m) { processEvent(EventBase(egid,sid,etid,dur,n,m)); }
00164   //! deprecated -- pass by reference instead;  this version posts the specified event and then deletes it after processing is complete
00165   /*! moving to pass by reference instead of pass by pointer to avoid questions about who deletes the event and the event's scope,
00166    *  also keeping the event on the stack is faster by avoiding unnecessary heap operations. */
00167   void postEvent(EventBase* e) ATTR_deprecated;
00168   //! posts the specified event, but doesn't delete it at the end -- equivalent to processEvent(e)
00169   void postEvent(const EventBase& e) { processEvent(e); }
00170 
00171   //! determines if timers need to be posted, and posts them if so.
00172   /*! Call this often to ensure accurate timers. */
00173   void processTimers();
00174   //! sends event to its trappers & listeners, but doesn't delete the event at the end (see also postEvent())
00175   /*! this posting method is supplied to allow an EventRouter to behave as a listener as 
00176    *  well -- the 'routers' really can form a sort of network, if desired.  postEvent() is
00177    *  probably a more memnomic interface to use in direct function calls however,
00178    *  so that is the one you should call. */
00179   void processEvent(const EventBase& e);
00180   //@}
00181 
00182   
00183   //!@name Listener/Trapper Recall
00184   
00185   //! returns true if the specified listener/trapper would receive any events that match the specified criteria
00186   bool isListeningAny(EventListener* el, EventBase::EventGeneratorID_t egid) { return listeners.verifyMappingAny(el,egid); }
00187   bool isListeningAny(EventListener* el, EventBase::EventGeneratorID_t egid, unsigned int sid) { return listeners.verifyMappingAny(el,egid,sid); }
00188   bool isListeningAll(EventListener* el, EventBase::EventGeneratorID_t egid) { return listeners.verifyMappingAll(el,egid); }
00189   bool isListeningAll(EventListener* el, EventBase::EventGeneratorID_t egid, unsigned int sid) { return listeners.verifyMappingAll(el,egid,sid); }
00190   bool isListening(EventListener* el, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid) { return listeners.verifyMapping(el,egid,sid,etid); }
00191   bool isListening(EventListener* el, const EventBase& e) { return listeners.verifyMapping(el,e.getGeneratorID(),e.getSourceID(),e.getTypeID()); }
00192   bool isTrappingAny(EventTrapper* el, EventBase::EventGeneratorID_t egid) { return trappers.verifyMappingAny(el,egid); }
00193   bool isTrappingAny(EventTrapper* el, EventBase::EventGeneratorID_t egid, unsigned int sid) { return trappers.verifyMappingAny(el,egid,sid); }
00194   bool isTrappingAll(EventTrapper* el, EventBase::EventGeneratorID_t egid) { return trappers.verifyMappingAll(el,egid); }
00195   bool isTrappingAll(EventTrapper* el, EventBase::EventGeneratorID_t egid, unsigned int sid) { return trappers.verifyMappingAll(el,egid,sid); }
00196   bool isTrapping(EventTrapper* el, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid) { return trappers.verifyMapping(el,egid,sid,etid); }
00197   bool isTrapping(EventTrapper* el, const EventBase& e) { return trappers.verifyMapping(el,e.getGeneratorID(),e.getSourceID(),e.getTypeID()); }
00198   //@}
00199   
00200   
00201   //!@name Listener/Trapper Detection
00202   
00203   /*!@brief <b>counts both listeners and trappers</b>, so generators can tell if it even needs to bother generating an event...*/
00204   /* Generators can also subscribe to the EventBase::erouterEGID event stream if
00205    * they wish to be notified when they gain or lose listeners (particularly the
00206    * first or last).\n
00207    * ... if a tree falls in a forest, and there's no one around to see it, does
00208    * it make a sound?\n
00209    * ... if Vision sees a ball in an image, and there's no listeners, does it
00210    * make an event? ;) */
00211   bool hasListeners(EventBase::EventGeneratorID_t egid) { return trappers.hasMapping(egid) || listeners.hasMapping(egid); }
00212   bool hasListeners(EventBase::EventGeneratorID_t egid, unsigned int sid) { return trappers.hasMapping(egid,sid) || listeners.hasMapping(egid,sid); }
00213   bool hasListeners(EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid) { return trappers.hasMapping(egid,sid,etid) || listeners.hasMapping(egid,sid,etid); }
00214   bool hasListeners(const EventBase& e) { return hasListeners(e.getGeneratorID(),e.getSourceID(),e.getTypeID()); }
00215   //@}
00216 
00217   
00218   //!@name Timer Management
00219   
00220   //! adds a timer if it doesn't exist, or resets the timer if it already exists.
00221   void addTimer(EventListener* el, unsigned int sid, unsigned int delay, bool repeat=true);
00222   void addTimer(EventListener* el, const EventBase& e, bool repeat=true) { addTimer(el,e.getSourceID(),e.getDuration(),repeat); } //!< calls the other addTimer() with the event's source id and duration, doesn't check to see if the generator is timerEGID
00223   
00224   //! clears all pending timers for listener @a el; see remove()
00225   void removeTimer(EventListener* el);
00226   void removeTimer(EventListener* el, unsigned int sid); //!< clears any pending timers with source id @a sid for listener @a el
00227   void removeAllTimers(); //!< clears all timers for all listeners
00228   unsigned int getNextTimer() { return (timers.size()==0 ? -1U : timers.front()->next); } //!< returns time of next timer activation
00229   //@}
00230 
00231   
00232   //!@name Listener Management
00233   
00234   //! Adds a listener for all events from a given event generator
00235   void addListener(EventListener* el, EventBase::EventGeneratorID_t egid);
00236   void addListener(EventListener* el, EventBase::EventGeneratorID_t egid, unsigned int sid); //!< Adds a listener for all types from a specific source and generator
00237   void addListener(EventListener* el, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid); //!< Adds a listener for a specific source id and type from a given event generator
00238   void addListener(EventListener* el, const EventBase& e); //!< Uses the generator, source, and type fields of @a e to add a listener for that specific tuple
00239 
00240   //! stops sending ALL events to the listener -- does not remove pending timers however (may need to call removeTimer(el) as well); see remove()
00241   void removeListener(EventListener* el); 
00242   //! stops sending specified events from the generator to the listener.
00243   void removeListener(EventListener* el, EventBase::EventGeneratorID_t egid);
00244   void removeListener(EventListener* el, EventBase::EventGeneratorID_t egid, unsigned int sid); //!< stops sending specified events from the generator to the listener.
00245   void removeListener(EventListener* el, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid); //!< stops sending specified events from the generator to the listener.
00246   void removeListener(EventListener* el, const EventBase& e); //!< Uses the generator, source, and type fields of @a e to remove a listener for that specific tuple
00247   
00248   //! stops all events and timers, shorthand for removeListener(el) and removeTimer(el); Note that trappers are separate, removeTrapper() is @e not called
00249   void remove(EventListener* el) { removeListener(el); removeTimer(el); }
00250 
00251   //@}
00252 
00253   //!@name Trapper Management
00254   
00255   //! Adds a trapper for a specific source id and type from a given event generator
00256   /*! Note that only the broadcasted timers can be trapped.  The EventListener which requested the timer will receive that timer before any trapping is done. */
00257   void addTrapper(EventTrapper* el, const EventBase& e);
00258   void addTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid); //!< Adds a trapper for all events from a given event generator
00259   void addTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid, unsigned int sid);  //!< Adds a trapper for all types from a specific source and generator
00260   void addTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid); //!< Adds a trapper for a specific source id and type from a given event generator
00261 
00262   void addTrapper(EventTrapper* el); //!< adds a trapper for ALL events
00263 
00264   //! stops sending specified events from the generator to the trapper.
00265   void removeTrapper(EventTrapper* el, const EventBase& e);
00266   void removeTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid); //!< stops sending specified events from the generator to the trapper.
00267   void removeTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid, unsigned int sid); //!< stops sending specified events from the generator to the trapper.
00268   void removeTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid); //!< stops sending specified events from the generator to the trapper.
00269 
00270   void removeTrapper(EventTrapper* el); //!< stops sending ALL events to the trapper
00271   //@}
00272 
00273  protected:
00274   //! Contains all the information needed to maintain a timer by the EventRouter
00275   struct TimerEntry {
00276     //! constructs an entry using the given value for next - useful for with TimerEntryPtrCmp
00277     explicit TimerEntry(unsigned int nxt) : el(NULL), sid(0), delay(0), next(nxt), repeat(false) {}
00278     //! constructs with the given values, sets next field automatically; see next
00279     TimerEntry(EventListener* e, unsigned int s, unsigned int d, bool r) : el(e), sid(s), delay(d), next(get_time()+delay), repeat(r) {}
00280     //! just does the default, i'm just being explicit since there's a pointer (no deep copy!)
00281     TimerEntry(const TimerEntry& t) : el(t.el), sid(t.sid), delay(t.delay), next(t.next), repeat(t.repeat) {}
00282     //! just does the default, i'm just being explicit since there's a pointer (no deep copy!)
00283     TimerEntry& operator=(const TimerEntry& t) { el=t.el; sid=t.sid; delay=t.delay; next=t.next; repeat=t.repeat; return *this; }
00284     //! will reset timer
00285     /*! @param d the time from now when the timer should go off (in milliseconds)
00286      *  @param r true if the timer should automatically repeat */
00287     void Set(unsigned int d, bool r) { delay=d; repeat=r; next=get_time()+delay; }
00288     EventListener* el;  //!< the listener to fire at
00289     unsigned int sid;   //!< the source id to fire with
00290     unsigned int delay; //!< the delay until firing
00291     unsigned int next;  //!< the time at which this timer will go off next
00292     bool repeat;        //!< if true, will reset after firing, else will be deleted
00293   };
00294   /*! @brief Used by STL to sort the timer list in order of activation time
00295    *  @see EventRouter::timers */
00296   class TimerEntryPtrCmp {
00297   public:
00298     //! Used by STL to sort the timer list in order of activation time; see timers
00299     /*! Since we remove NULLs before sorting, shouldn't need to check here (and I want to know if i'm wrong)
00300      *  @return (a->next<b->next) */
00301     bool operator()(const TimerEntry* const a, const TimerEntry* const b) const { return (a->next<b->next); }
00302   };
00303   typedef std::vector<TimerEntry*>::iterator timer_it_t; //!< makes code more readable
00304   std::vector<TimerEntry*> timers;         //!< the list of timer entries being maintained, kept sorted by time they go active
00305 
00306   //! just for debugging
00307   void chkTimers() {
00308     unsigned int last=0;
00309     for(timer_it_t it=timers.begin(); it!=timers.end(); it++) {
00310       if(last>(*it)->next) {
00311         dispTimers();
00312         return;
00313       }
00314       last=(*it)->next;
00315     }
00316   }
00317   //! just for debugging
00318   void dispTimers() {
00319     std::cout << "out of order timers " << get_time() << " :\t";
00320     unsigned int last=0;
00321     for(timer_it_t it=timers.begin(); it!=timers.end(); it++) {
00322       if(last>(*it)->next)
00323         std::cout << "##";
00324       std::cout << (last=(*it)->next) << '\t';
00325     }
00326     std::cout << std::endl;
00327   }
00328   
00329   //! Does the actual storage of the mapping between EventBase's and the EventListeners/EventTrappers who should receive them
00330   /*! Actually only stores void*'s, so it's more general than just Listeners or Trappers */
00331   class EventMapper {
00332   public:
00333     //! constructor
00334     EventMapper();
00335 
00336     void addMapping(void* el, EventBase::EventGeneratorID_t egid) { allevents[egid].push_back(el); } //!< Adds a listener for all events from a given event generator
00337     void addMapping(void* el, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid); //!< Adds a listener for a specific source id and type from a given event generator
00338 
00339     //! Removes a listener for all events from a given event generator, returns true if something was actually removed
00340     /*! Doesn't necessarily remove the vector or mapping if this was the last listener, use clean() to do that */
00341     bool removeMapping(void* el, EventBase::EventGeneratorID_t egid); 
00342 
00343     //! Removes a listener for a specific source id and type from a given event generator, returns true if something was actually removed
00344     /*! Doesn't necessarily remove the vector or mapping if this was the last listener, use clean() to do that */
00345     bool removeMapping(void* el, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid);
00346 
00347     void clean(); //!<removes empty data structures for all event generators
00348     void clean(EventBase::EventGeneratorID_t egid); //!< removes empty data structures associated with a single event generator
00349     void clear(); //!<Resets the mapping
00350 
00351     //@{
00352     //! so stuff can tell if it even needs to bother generating an event...
00353     /*! ... if a tree falls in a forest, and there's no one around to see it, does it make a sound?\n
00354         ... if Vision sees a ball in an image, and there's no listeners, does it make an event? ;) \n
00355         @return true if it has any listeners, false otherwise */
00356     bool hasMapping(EventBase::EventGeneratorID_t egid) const;
00357     bool hasMapping(EventBase::EventGeneratorID_t egid, unsigned int sid) const;
00358     bool hasMapping(EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid) const;
00359     //@}
00360 
00361     //! builds a list of all listeners which should receive the event, templated to typecast the pointers for you
00362     /*! @param e the key event
00363      *  @param listeners upon return, the resulting list of listeners @a e maps to\n
00364      *  @a listeners is not cleared prior to building, new listeners are pushed on end\n
00365      *  Results are in the order: all specific matches first, all generator listeners second, in order they were added to the EventMapper.*/
00366     template<class T>
00367     void getMapping(const EventBase& e, std::vector<T*>& listeners) const;
00368 
00369     //! Used to make sure that the specified listener exists for the given event
00370     /*! This is needed because after we call processEvent on a lister, we can't assume
00371      *  that no other listeners have been modified - one listener could cause another
00372      *  to turn off.  If that has happened, we shouldn't send the event, even if it
00373      *  was in the queue originally. */
00374     bool verifyMapping(void * listener, const EventBase& e) const { return verifyMapping(listener,e.getGeneratorID(),e.getSourceID(),e.getTypeID()); }
00375     //! Used to make sure that the specified listener exists for the given event
00376     /*! This is needed because after we call processEvent on a lister, we can't assume
00377      *  that no other listeners have been modified - one listener could cause another
00378      *  to turn off.  If that has happened, we shouldn't send the event, even if it
00379      *  was in the queue originally. */
00380     bool verifyMapping(void * listener, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid) const;
00381 
00382     //! Needed to complete EventRouter::isListening suite
00383     /*! Only checks #allevents */
00384     bool verifyMappingAll(void * listener, EventBase::EventGeneratorID_t egid) const;
00385     //! Needed to complete EventRouter::isListening suite
00386     /*! Checks both #allevents and #filteredevents */
00387     bool verifyMappingAny(void * listener, EventBase::EventGeneratorID_t egid) const;
00388 
00389     //! Needed to complete EventRouter::isListening suite
00390     /*! Checks both #allevents and #filteredevents, must be found in all */
00391     bool verifyMappingAll(void * listener, EventBase::EventGeneratorID_t egid, unsigned int sid) const;
00392     //! Needed to complete EventRouter::isListening suite
00393     /*! Checks both #allevents and #filteredevents, can be found in either */
00394     bool verifyMappingAny(void * listener, EventBase::EventGeneratorID_t egid, unsigned int sid) const;
00395 
00396   protected:
00397     //! a mapping from source IDs (unsigned ints), each to a vector of pointers to listeners
00398     /*! main use in filteredevents @see filteredevents */
00399     typedef std::map<unsigned int,std::vector<void*>,std::less<unsigned int> > SIDtoListenerVectorMap_t;
00400     
00401     //! an array of vectors of pointers to listeners... in other words, a vector of listener pointers for each generator
00402     std::vector<void*> allevents[EventBase::numEGIDs];
00403     //! not for the faint of heart: a matrix of mappings to vectors of pointers to listeners
00404     SIDtoListenerVectorMap_t* filteredevents[EventBase::numEGIDs][EventBase::numETIDs];
00405 
00406   private:
00407     EventMapper(const EventMapper&);           //!< this shouldn't be called...
00408     EventMapper& operator=(const EventMapper&); //!< this shouldn't be called...
00409   };
00410 
00411   EventMapper trappers;  //!< A mapping of which EventTrapper's should get a chance to trap the event
00412   EventMapper listeners; //!< A mapping of which EventListener's should receive events
00413 
00414   //! contains information regarding the progress of posting an event
00415   /*! This allows us to resume and complete the posting of the "current" event before processing a new incoming event */
00416   class PostingStatus {
00417   public:
00418     //! constructor
00419     PostingStatus(const EventMapper& eventTrappers, const EventMapper& eventListeners, const EventBase& event)
00420       : trappers(eventTrappers), listeners(eventListeners), t(), tit(), l(), lit(), e(event)
00421     { trappers.getMapping(e,t); tit=t.begin(); listeners.getMapping(e,l); lit=l.begin(); }
00422     //! begins or resumes sending the event #e to trappers and listeners in #t and #l
00423     void process();
00424   protected:
00425     const EventMapper& trappers; //!< the current trapper mapping, used to verify each entry in #t is still valid before processing it
00426     const EventMapper& listeners; //!< the current listener mapping, used to verify each entry in #l is still valid before processing it
00427     std::vector<EventTrapper*> t; //!< list of trappers which were subscribed when the PostingStatus instance was constructed
00428     std::vector<EventTrapper*>::const_iterator tit; //!< current position within #t
00429     std::vector<EventListener*> l; //!< list of listeners which were subscribed when the PostingStatus instance was constructed
00430     std::vector<EventListener*>::const_iterator lit; //!< current position within #l
00431     const EventBase& e; //!< the event being processed
00432   };
00433   std::queue<PostingStatus*> postings; //!< stores calls to post() currently in progress -- may grow if one postEvent() triggers another; this allows us to finish processing of the original postEvent() before starting the second.
00434 };
00435 
00436 //! a global router for cross communication, probably the most common usage, although perhaps there may be times you'd rather have multiple event routers for smaller sections
00437 extern EventRouter * erouter;
00438 
00439 /*! @file
00440  * @brief Describes EventRouter class, for distribution and trapping of events to listeners
00441  * @author ejt (Creator)
00442  *
00443  * $Author: ejt $
00444  * $Name: tekkotsu-3_0 $
00445  * $Revision: 1.35 $
00446  * $State: Exp $
00447  * $Date: 2006/10/03 21:09:04 $
00448  */
00449 
00450 #endif

Tekkotsu v3.0
Generated Wed Oct 4 00:03:43 2006 by Doxygen 1.4.7