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