SimCallback.H

Go to the documentation of this file.
00001 /*!@file Simulation/SimCallback.H A callback when some SimEvent is received by SimEventQueue */
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@pollux.usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Simulation/SimCallback.H $
00035 // $Id: SimCallback.H 13065 2010-03-28 00:01:00Z itti $
00036 //
00037 
00038 #ifndef SIMULATION_SIMCALLBACK_H_DEFINED
00039 #define SIMULATION_SIMCALLBACK_H_DEFINED
00040 
00041 #include <typeinfo>
00042 #include "rutz/shared_ptr.h"
00043 #include "rutz/demangle.h"
00044 #include "Simulation/SimEventQueueFlag.H"
00045 #include "Util/log.H"
00046 #include "Util/sformat.H"
00047 
00048 class SimCallbackClient;
00049 class SimEventQueue;
00050 class SimEvent;
00051 class SimModule;
00052 
00053 //! A SimEventQueue callback for SimModule
00054 /*! This is the base class. We will then create template derived
00055     classes (see ModelParamBase and ModelParam for a similar
00056     idea). The basic idea here is that a SimModule should, at
00057     construction, declare a series of callbacks which SimEventQueue
00058     will automatically call when the appropriate SimEvent objects are
00059     received by the queue. The standard C++ way of doing this
00060     typically would involve a callback class, and then derivatives of
00061     this, each one implementing the operator() in various ways
00062     (functor paradigm). However, this is not very convenient as
00063     typically the callback function would want to access the data
00064     members of its SimModule. Hence, we here use a different strategy,
00065     first declaring a function which is a member of SimModule and
00066     implements the actual code to be executed during callback, and
00067     second implementing a template "callback hook" whose role is just
00068     to connect that member function to the SimEventQueue.  SimCallback
00069     is just the hook. */
00070 class SimCallbackBase {
00071 public:
00072   //! Constructor
00073   SimCallbackBase(SimCallbackClient *smod, const int priority = 0,
00074                   const SimEventQueueFlag flags = SEQ_UNMARKED | SEQ_MARK,
00075                   const SimModule* eventsource = 0);
00076 
00077   //! Destructor
00078   virtual inline ~SimCallbackBase();
00079 
00080   //! What's our underlying SimEvent type?
00081   /*! Forbidden in the base class. */
00082   virtual const std::type_info& etype() const = 0;
00083 
00084   //! What's our underlying SimCallbackClient (usually SimModule) type?
00085   /*! Forbidden in the base class. */
00086   virtual const std::type_info& mtype() const = 0;
00087 
00088   //! Get the priority
00089   inline int priority() const;
00090 
00091   //! Get the SimCallbackClient
00092   virtual SimCallbackClient *client() const = 0;
00093 
00094   //! Get the flags
00095   inline const SimEventQueueFlag sflags() const;
00096 
00097   //! Get the desired event source, if any
00098   inline const SimModule* eventsrc() const;
00099 
00100   //! Get some string description of ourselves, for printing/debug
00101   inline std::string toString() const;
00102 
00103   //! Execute the callback
00104   /*! This will call the callback method on the callback client,
00105       passing it the queue and the event. */
00106   virtual void execute(SimEventQueue& q, rutz::shared_ptr<SimEvent>& e) = 0;
00107 
00108 protected:
00109   int itsPriority;
00110   SimEventQueueFlag itsFlags;
00111   const SimModule *itsEventSrc;
00112 
00113 private:
00114   SimCallbackBase(const SimCallbackBase& s);      //!< forbid copy-contruction
00115   SimCallbackBase& operator=(const SimCallbackBase& s); //!< forbid copy
00116 };
00117 
00118 // ######################################################################
00119 //! Template class for SimEventQueue callbacks
00120 /*! Method 'meth' will be called by the SimEventQueue when a
00121   desired event is received. Typical usage is as follows:
00122 
00123   in your .H:
00124 
00125   \code
00126 
00127   // your class should inherit from at least SimCallbackClient,
00128   // typically it will inherit from SimModule which itself iherits
00129   // from SimCallbackClient:
00130   class MySimModule : public SimModule {
00131   ...
00132   private:
00133   // our method to run when SimEventX is posted to the queue,
00134   // will be called by SimEventQueue:
00135   void processX(SimEventQueue& q, rutz::shared_ptr<SimEventX>& e);
00136 
00137   // a hook by which we will let our SimEventQueue know about processX():
00138   SimCallback<MySimModule, SimEventX> itsCBx;
00139   \endcode
00140 
00141   in your .C, in the constructor of your class (which must be
00142   a SimCallbackClient derivative), in the initalizer list:
00143 
00144   \code
00145   MySimModule::MySimModule() :
00146   ...
00147   itsCBx(this, &MySimModule::processX),
00148   ...
00149   { ... }
00150   \endcode
00151 
00152   and finally you also should implement MySimModule::processX(). */
00153 
00154 template <class Module, class Event>
00155 class SimCallback : public SimCallbackBase
00156 {
00157 public:
00158   //! Definition for the format and args of the called-back method
00159   typedef void (Module::*Method)(SimEventQueue&, rutz::shared_ptr<Event>&);
00160 
00161   //! Constructor
00162   inline SimCallback(Module* mod, Method meth, const int priority = 0,
00163                      const SimEventQueueFlag flags = SEQ_UNMARKED | SEQ_MARK,
00164                      const SimModule* eventsource = 0);
00165 
00166   //! Destructor
00167   virtual inline ~SimCallback();
00168 
00169   //! What's our underlying SimEvent type?
00170   virtual const std::type_info& etype() const;
00171 
00172   //! What's our underlying SimCallbackClient (usually SimModule) type?
00173   virtual const std::type_info& mtype() const;
00174 
00175   //! Get the SimCallbackClient
00176   virtual inline SimCallbackClient *client() const;
00177 
00178   //! Call the callback
00179   virtual inline void execute(SimEventQueue& q, rutz::shared_ptr<SimEvent>& e);
00180 
00181 private:
00182   Module* itsModule;
00183   Method itsMethod;
00184 
00185   template <class M, class E> SimCallback(const SimCallback<M, E>& s);      //!< forbid copy-contruction
00186   template <class M, class E> SimCallback<Module, Event>& operator=(const SimCallback<M, E>& s); //!< forbid copy
00187 };
00188 
00189 // ######################################################################
00190 //! Macro to declare a SimCallback (use in your .H)
00191 /*! This will declare a SimCallback called itsCallback[eventname] and a
00192   function called on[eventname] which you will need to implement. For example:
00193 
00194   \code
00195   SIMCALLBACK_DECLARE(Retina, SimEventInputFrame);
00196   \endcode
00197 
00198   is equivalent to:
00199 
00200   \code
00201   void onSimEventInputFrame(SimEventQueue& q, rutz::shared_ptr<SimEventInputFrame>& e);
00202   SimCallback<Retina, SimEventInputFrame> itsCallbackSimEventInputFrame;
00203   \endcode
00204 
00205   then make sure you use the macro SIMCALLBACK_INIT in your class
00206   constructor, and that you implement onSimEventInputFrame() somewhere
00207   in your .C file. In our example:
00208 
00209   \code
00210   Retina::Retina(...) :
00211     ...,
00212     SIMCALLBACK_INIT(SimEventInputFrame)
00213   { }
00214 
00215   void Retina::onSimEventInputFrame(SimEventQueue& q, rutz::shared_ptr<SimEventInputFrame>& e)
00216   { do_something(); }
00217   \endcode
00218 
00219   Have a look at Retina and other modules in src/Neuro for examples of usage. */
00220 #define SIMCALLBACK_DECLARE(classname, eventname)                             \
00221   void on##eventname(SimEventQueue& q, rutz::shared_ptr<eventname>& e);       \
00222   typedef classname itsSimCallbackClassTypeFor##eventname;                    \
00223   SimCallback<classname, eventname> itsCallback##eventname;
00224 
00225 //! Init a SimCallback created by SIMCALLBACK_DECLARE
00226 /*! Takes possible optional arguments which are the ones that have
00227     default values in the SimCallback constructor, namely:
00228       const int priority = 0,
00229       const SimEventQueueFlag flags = SEQ_UNMARKED | SEQ_MARK,
00230       const SimModule* eventsource = 0. */
00231 #define SIMCALLBACK_INIT(eventname, ...)                                      \
00232   itsCallback##eventname(this, &itsSimCallbackClassTypeFor##eventname::on##eventname, ## __VA_ARGS__ )
00233 
00234 // ######################################################################
00235 //! Functor used to compare two SimCallbackBase objects, sorting by priority
00236 struct SimCallbackCompare
00237 {
00238   bool operator()(const SimCallbackBase *s1, const SimCallbackBase *s2) const
00239   { return (s1->priority() < s2->priority()); }
00240 };
00241 
00242 
00243 // ######################################################################
00244 // Inline function implementations:
00245 // ######################################################################
00246 SimCallbackBase::~SimCallbackBase()
00247 { }
00248 
00249 int SimCallbackBase::priority() const
00250 { return itsPriority; }
00251 
00252 const SimEventQueueFlag SimCallbackBase::sflags() const
00253 { return itsFlags; }
00254 
00255 const SimModule* SimCallbackBase::eventsrc() const
00256 { return itsEventSrc; }
00257 
00258 std::string SimCallbackBase::toString() const
00259 {
00260   return sformat("%s callback for %s [pri=%d]", rutz::demangled_name(this->etype()),
00261                  rutz::demangled_name(this->mtype()), this->priority());
00262 }
00263 
00264 template <class Module, class Event>
00265 SimCallback<Module, Event>::
00266 SimCallback(Module* mod, SimCallback<Module, Event>::Method meth,
00267             const int priority,  const SimEventQueueFlag flags,
00268             const SimModule* eventsource) :
00269   SimCallbackBase(mod, priority, flags, eventsource), itsModule(mod), itsMethod(meth)
00270 { }
00271 
00272 template <class Module, class Event>
00273 SimCallback<Module, Event>::~SimCallback()
00274 { }
00275 
00276 template <class Module, class Event>
00277 const std::type_info& SimCallback<Module, Event>::etype() const
00278 { return typeid(Event); }
00279 
00280 template <class Module, class Event>
00281 const std::type_info& SimCallback<Module, Event>::mtype() const
00282 { return typeid(Module); }
00283 
00284 template <class Module, class Event>
00285 SimCallbackClient* SimCallback<Module, Event>::client() const
00286 { return itsModule; }
00287 
00288 template <class Module, class Event>
00289 void SimCallback<Module, Event>::
00290 execute(SimEventQueue& q, rutz::shared_ptr<SimEvent>& e)
00291 {
00292   // Make sure e is of type Event:
00293   rutz::shared_ptr<Event> ee; dyn_cast_to_from(ee, e);
00294   if (ee.is_valid() == false)
00295     LFATAL("Passed SimEvent does not derive from '%s'", rutz::demangled_name(typeid(Event)));
00296 
00297   // want to learn a new exotic syntax? calling a pointer to member function
00298   (itsModule->*itsMethod)(q, ee);
00299 };
00300 
00301 // ######################################################################
00302 /* So things look consistent in everyone's emacs... */
00303 /* Local Variables: */
00304 /* mode: c++ */
00305 /* indent-tabs-mode: nil */
00306 /* End: */
00307 
00308 #endif // SIMULATION_SIMCALLBACK_H_DEFINED
Generated on Sun May 8 08:06:50 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3