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