00001 /*!@file Component/ModelComponent.H base class for parameterized model components */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 // 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/Component/ModelComponent.H $ 00035 // $Id: ModelComponent.H 11019 2009-03-11 20:57:11Z itti $ 00036 // 00037 00038 #ifndef MODELCOMPONENT_H_DEFINED 00039 #define MODELCOMPONENT_H_DEFINED 00040 00041 #include "Component/ParamClient.H" 00042 #include "Component/ModelParamBase.H" 00043 #include "Util/Types.H" 00044 #include "Util/log.H" 00045 #include "nub/object.h" 00046 #include "nub/ref.h" 00047 #include "rutz/shared_ptr.h" 00048 00049 #include <iosfwd> 00050 #include <string> 00051 00052 //! A convenience function for making a rutz::shared_ptr out of a raw pointer. 00053 template <class T> 00054 inline nub::ref<T> makeSharedComp(T* t) { return nub::ref<T>(t); } 00055 00056 class ParamMap; 00057 class OptionManager; 00058 00059 //! Type for bitwise-or'ed combinations of ModelComponent flags 00060 typedef int ModelFlag; 00061 00062 //! placeholder for "no flags" 00063 const ModelFlag MC_NO_FLAGS = 0; 00064 00065 //! do operations recursively on subcomponents 00066 const ModelFlag MC_RECURSE = (1 << 0); 00067 00068 //! ignore missing param values, if possible (not all ops allow this flag) 00069 const ModelFlag MC_IGNORE_MISSING = (1 << 1); 00070 00071 //! Provide some information about howto save() things 00072 /*! Base class is empty, but derivations of ModelComponent, like, for 00073 example SimModule and derivatives, may use a derivation of 00074 ModelComponentSaveInfo which actually contains some info: */ 00075 class ModelComponentSaveInfo { 00076 public: 00077 //! Default constructor 00078 ModelComponentSaveInfo() { } 00079 00080 //! Virtual destructor to ensure safe destruction of derived objects 00081 virtual ~ModelComponentSaveInfo() { } 00082 }; 00083 00084 //! Base class for parameterized model components 00085 /*! The goal is to provide a unified interface by which tunable 00086 parameters can be set, read, or exported as command-line options or 00087 in parameter maps or files, so that executables using a variable 00088 collection of model components can easily be built and configured 00089 using command-line options and config files. To this end, 00090 ModelComponent provides a set of facilities that allow it to hold a 00091 number of ModelParamBase data members. A ModelComponent also holds a 00092 list of sub-components that are ModelComponent as well, and many of 00093 the ModelComponent functions will first apply to the component 00094 itself, then recursively to its subcomponents. The ModelParamBase 00095 are the tunable parameters that are persistent and may be associated 00096 with a command-line option; see ModelParam.H for details. A 00097 ModelComponent is attached to a OptionManager that will handle 00098 option parsing and ModelParamBase load/save. A ModelComponent may 00099 request its master to associate some of its ModelParamBase data 00100 members with command-line options. Command-line option definitions 00101 are typically given in one master file per source directory 00102 (e.g. Devices/DeviceOpts.C, Media/MediaOpts.C, Neuro/NeuroOpts.C), 00103 although some components may also define private command-line 00104 options internally in their own .C files. Command-line parsing will 00105 set the value of ALL ModelParamBase objects in all ModelComponent 00106 objects and their subcomponents that have requested the option to 00107 the value specified on the command line. So this mechanism should be 00108 used sparingly, for parameters that may be used across a variety of 00109 models and a variety of ModelComponent derivatives. 00110 00111 There is one trick to be aware of with respect to the basic 00112 operation and setup of ModelComponent. For speed reasons, we want 00113 our ModelParam parameters to be true data members, so that we can 00114 access them as efficiently as normal data members (rather than 00115 having to first look them up by name). On the other hand, the 00116 ModelComponent must also be able to produce a list of all its 00117 ModelParam members, so that they can be saved to a ParamMap. To 00118 resolve this, ModelComponent both holds each ModelParam as a regular 00119 data member, and a list of pointers to all its ModelParam 00120 members. In addition, this list keeps track of which model params 00121 are affiliated with command-line options, as well as which should 00122 actually be exported on the command-line. This list is automatically 00123 maintained when the ModelParam objects are constructed and 00124 destroyed, so that the user does not have to worry about it. */ 00125 class ModelComponent : public ParamClient, public virtual nub::object 00126 { 00127 public: 00128 // ###################################################################### 00129 /*! @name Constructors and Destructors */ 00130 //@{ 00131 00132 //! Constructor 00133 /*! Typically, in the constructor you should perform all 00134 initializations that are independent of the values of your 00135 ModelParam data members. Since the command-line usually has not 00136 been parsed yet at the time you construct your various 00137 ModelComponent objects, however, the start() function below is 00138 provided to allow you to perform additional initializations after 00139 the command-line has been parsed and the ModelParam data members 00140 have been configured. 00141 @param mgr our option manager; see OptionManager.H 00142 @param descrName a human-readable descriptive name 00143 @param tagname a computer-oriented unique name (used for storage in ParamMap) 00144 @param crealm the realm in which this component lives, used for partitioning 00145 the SimEvent space into possibly distinct realms. */ 00146 ModelComponent(OptionManager& mgr, const std::string& descrName, 00147 const std::string& tagName, 00148 const std::string& crealm = "World"); 00149 00150 //! Constructor overload without an OptionManager 00151 /*! In this case, you must call setManager() before using any other 00152 functions. In fact, if you aren't ModelManager, you probably 00153 shouldn't be using this constructor! (ModelManager needs it due 00154 to an implementation quirk related to multiple inheritance). */ 00155 ModelComponent(const std::string& descrName, 00156 const std::string& tagName, 00157 const std::string& crealm = "World"); 00158 00159 //! Virtual destructor ensures proper destruction of derived classes 00160 virtual ~ModelComponent(); 00161 00162 //! Start the component 00163 /*! This will start the component by triggering the following 00164 sequence of actions: 00165 - Check if we are already started and emit a fatal error if so 00166 - Call start1() that may be overloaded by derived classes 00167 - Call start() on all our subcomponents 00168 - Call start2() that may be overloaded by derived classes 00169 - Switch us to "started" state, in which modifying our ModelParam 00170 values externally is forbidden 00171 00172 Derived classes should overload start1() and start2() as a way to 00173 get the component started, once the command-line options and 00174 config files have been parsed and all the ModelParam objects have 00175 been configured. Default no-op implementations are provided for 00176 start1() and start2(), so if you don't need to do anything to 00177 start your component, you don't need to implement start1() and 00178 start2(). Because this is a recursive call on our sub-components, 00179 typically you only need to call it once on your root 00180 ModelComponent (probably ModelManager) to get your entire 00181 hierarchy of ModelComponent objects started. */ 00182 void start(); 00183 00184 //! Did we already get a call to start()? 00185 bool started() const; 00186 00187 //! Stop the component 00188 /*! This will stop the component by triggering the following 00189 sequence of actions: 00190 - Check if we are already started and emit a fatal error if not 00191 - Call stop1() that may be overloaded by derived classes 00192 - Call stop() on all our subcomponents 00193 - Call stop2() that may be overloaded by derived classes 00194 - Switch us out of "started" state, so that modifying our ModelParam 00195 values externally is allowed 00196 00197 Derived classes should overload stop1() and stop2() as a way to 00198 get the component stopped, once the command-line options and 00199 config files have been parsed and all the ModelParam and objects 00200 have been configured. Default no-op implementations are provided 00201 for stop1() and stop2(), so if you don't need to do anything to 00202 stop your component, you don't need to implement stop1() and 00203 stop2(). Because this is a recursive call on our sub-component, 00204 typically you only need to call it once on your root 00205 ModelComponent (probably ModelManager) to get the entire hierarchy 00206 of ModelComponent objects stopped. */ 00207 void stop(); 00208 00209 //! Signify that our ModelManager just got destroyed 00210 /*! This should not be called manually, but will be called from 00211 within our parent ModelComponent's destructor. It will ensure 00212 that we do not try to unregister with our ModelManager if the 00213 manager is destroyed before us. */ 00214 void managerDestroyed(); 00215 00216 //! Get our manager. 00217 OptionManager& getManager() const; 00218 //@} 00219 00220 // ###################################################################### 00221 /*! @name Name functions */ 00222 //@{ 00223 00224 //! Get a human-readable descriptive name for this component. 00225 /*! This is NOT intended to be a name for programmatic use (such as 00226 for indexing into associative arrays). It is not necessarily 00227 unique on a per-object basis; it's possible that all objects of 00228 the same class return the same descriptiveName(). */ 00229 std::string descriptiveName() const; 00230 00231 //! Change this component's descriptive name. 00232 void setDescriptiveName(const std::string& name); 00233 00234 //! Get a programmer-usable tag name for this object. 00235 /*! This is intended to be unique among component objects, so that 00236 this string could be used for associate-array indexing, for 00237 example. */ 00238 std::string tagName() const; 00239 00240 //! Change this component's tag name. 00241 void setTagName(const std::string& name); 00242 00243 //! Get the realm 00244 std::string realm() const; 00245 00246 //! Set the realm 00247 /*! This will throw a fatal exception if the component is in started 00248 state. This is a recursive call which will propagate to all 00249 subcomponents. */ 00250 void setRealm(const std::string& crealm); 00251 00252 //@} 00253 00254 // ###################################################################### 00255 /*! @name Sub-Component management functions */ 00256 //@{ 00257 00258 //! Get this component's parent ModelComponent, or NULL if it has no parent. 00259 /*! Internally, each component stores a weak smart pointer to its 00260 parent, while the parent stores a strong smart pointer to the 00261 child. This avoids unbreakable reference-counting cycles, but 00262 still lets us traverse the parent-child in both directions 00263 component tree using getParent() and subComponent(). */ 00264 ModelComponent* getParent() const; 00265 00266 //! Get this component's root parent (the parent of all parents in our tree) 00267 /*! If this component has no parent, then getRootObject() returns a 00268 pointer to this component itself. */ 00269 ModelComponent* getRootObject(); 00270 00271 //! Get this component's root parent (the parent of all parents in our tree) 00272 /*! If this component has no parent, then getRootObject() returns a 00273 pointer to this component itself. */ 00274 const ModelComponent* getRootObject() const; 00275 00276 //! Add a subcomponent to our internal list; return its index 00277 /*! NOTE that by default this will set the realm of the subcomponent (and its subs) to our realm */ 00278 uint addSubComponent(const nub::ref<ModelComponent>& subc, const bool propagate_realm = true); 00279 00280 //! Remove a subcomponent from our internal list, by address 00281 /*! This will only remove the component from our list of registered 00282 subcomponents, but will not attempt to destroy it. If removeall 00283 is true, then all components matching subc are removed; 00284 otherwise, only the first is removed. Returns the number of 00285 subcomponents that were removed. */ 00286 int removeSubComponent(const ModelComponent& subc, bool removeall = false); 00287 00288 //! Remove a subcomponent by nub:ref. 00289 void removeSubComponent(const nub::ref<ModelComponent>& subc); 00290 00291 //! Remove a subcomponent from our internal list, by index 00292 /*! This will only remove the component from our list of registered 00293 subcomponents, but will not attempt to destroy it. */ 00294 void removeSubComponent(const uint idx); 00295 00296 //! Remove a subcomponent from our internal list, by tagName 00297 /*! This will only remove the component from our list of registered 00298 subcomponents, but will not attempt to destroy it. */ 00299 void removeSubComponent(const std::string& tagname); 00300 00301 //! Remove all our subcomponents 00302 void removeAllSubComponents(); 00303 00304 //! Access a sub-component by index 00305 nub::ref<ModelComponent> subComponent(const uint idx) const; 00306 00307 //! Access a sub-component by tagname 00308 /*! @param flags if containing MC_RECURSE, will look not only in our 00309 subcomponents but also recursively in their subcomponents 00310 (depth-first search)*/ 00311 nub::ref<ModelComponent> subComponent(const std::string& tagname, 00312 const ModelFlag flags = 0) const; 00313 00314 //! Get current number of subcomponents 00315 uint numSubComp() const; 00316 00317 //! Return true if we have a subcomponent by that tagname 00318 /*! @param flags if containing MC_RECURSE, will look not only in our 00319 subcomponents but also recursively in their subcomponents 00320 (depth-first search)*/ 00321 bool hasSubComponent(const std::string& tagname, 00322 const ModelFlag flags = 0) const; 00323 00324 //! Return true if we have the pointee as subcomponent 00325 /*! @param flags if containing MC_RECURSE, will look not only in our 00326 subcomponents but also recursively in their subcomponents 00327 (depth-first search)*/ 00328 bool hasSubComponent(const nub::soft_ref<ModelComponent>& c, 00329 const ModelFlag flags = 0) const; 00330 00331 //! Show our ModelParam internals and those of our subcomponents 00332 void printout(std::ostream& s, const std::string& prefix = "") const; 00333 00334 //! Reset a model component and propagate the request to the sub-components 00335 /*! For each ModelComponent reset should set it into the state that 00336 it was just after calling the constructor. It will depend on the 00337 component what exactly that involves. 00338 00339 @param flags if containing MC_RECURSE, then we recursively 00340 reset() our subcomponents as well 00341 00342 PROGRAMMER NOTE: This function is not virtual, so you should not 00343 try to override this function in your derived class; instead 00344 override reset1() and/or reset2(). In those overrides, be sure 00345 to call your base class's version of reset1() or reset2(). 00346 */ 00347 void reset(const ModelFlag flags); 00348 00349 //! Save/display our current state 00350 /*! Over the course of a program run, once in a while it may be 00351 desirable to broadcast an order to all ModelComponents to save 00352 and/or display their current state or internals. This function 00353 achieves this. Like for start(), stop() and reset(), this is a 00354 usually recursive call, and derived classes should not override this 00355 function, but should instead override save1() (called before we 00356 recurse through our subcomponents) and save2() (called after we 00357 have recursed through our subcomponents). Default implementations 00358 for save1() and save2() are provided which are no-ops. */ 00359 void save(const ModelComponentSaveInfo& sinfo, 00360 const ModelFlag flags = MC_RECURSE); 00361 00362 //@} 00363 00364 // ###################################################################### 00365 /*! @name Access to tunable ModelParam's */ 00366 //@{ 00367 00368 //! Export some of our ModelParam parameters as command-line-options 00369 /*! This should be called once on the model manager to decide which 00370 sets of ModelParam paremeters should become command-line 00371 options; the call will then recurse through all ModelComponent 00372 objects that have been registered with the manager. This is 00373 provided so that external meta-knowledge about what a collection 00374 of ModelComponent objects forming a computational model can be 00375 used to decide on which command-line options are relevant: for 00376 instance, if you build a model that has no OutputFrameSeries, 00377 then you will not be able to call saveResults() on your Brain or 00378 other objects, so you would not want to export command-line 00379 options that relate to which results should be saved. This is 00380 handled by the exportFlag member of each ModelOptionDef, which 00381 must match the ModelManager's current export mask (set by 00382 ModelManager::allowOptions()) in order for that option to 00383 actually be exported. 00384 00385 HISTORICAL NOTE: It used to be that every subclass of 00386 ModelComponent would need to override exportOptions(), and 00387 explicitly request that each model param be exported. This is no 00388 longer the case -- instead, when each OModelParam is constructed 00389 in the subclass's constructor, it ends up calling 00390 registerOptionedParam() on the ModelComponent, which adds the 00391 param to our list of params, but also marks the param for 00392 command-line export whenever exportOptions() is finally 00393 called. For those rare cases where you do not want an 00394 OModelParam exported to the command-line, you can call 00395 forgetExports(), and then explicitly re-export any desired 00396 options using doRequestOption(). 00397 */ 00398 void exportOptions(const ModelFlag flags); 00399 00400 //! Check for named param in this component (and possibly its subcomponents) 00401 /*! Use this to verify that a param exists before doing a 00402 getModelParamVal() or setModelParamVal(), since those functions 00403 will throw an exception if the named param is non-existent. */ 00404 bool hasModelParam(const std::string& name, const ModelFlag flags = 0) const; 00405 00406 //! Parse a parameter value given as string and set the param 00407 /*! Should not be needed in normal operation, inefficient text-based 00408 interface. In normal operation, the internals of the 00409 ModelComponent derivative will directly access the ModelParam, 00410 not external people. If you want to provide external access to 00411 your ModelParam values, you should implement a wrapper for them 00412 in your ModelComponent derivative (e.g., implement a function 00413 setSize() that will set the value of your Size ModelParam). 00414 Returns true if the ModelParam was found and set. Throws a fatal 00415 error if the ModelComponent was started, to avoid external 00416 people messing around with our ModelParam values during 00417 operation of the component. 00418 00419 @param name the ModelParam tagname 00420 @param value the parameter value, to be parsed 00421 @param flags bitwise-or'ed combination of MC_RECURSE, MC_IGNORE_MISSING 00422 00423 HISTORICAL NOTE: In the past, subclasses would override 00424 setModelParamString() if they needed special handling when param 00425 values changed, this is no longer the case -- instead subclasses 00426 should override paramChanged(); see additional documentation 00427 there. 00428 */ 00429 void setModelParamString(const std::string& name, 00430 const std::string& value, 00431 const ModelFlag flags = 0); 00432 00433 //! Set a parameter value 00434 /*! This is slow, as it will search for the ModelParam by name. If 00435 you need efficient access to ModelParam values, you should 00436 define a wrapper method in your ModelComponent derivative. In 00437 normal operation, indeed, only the methods of the ModelComponent 00438 derivative should directly access the ModelParam, not external 00439 people. Returns true if the ModelParam was found and set. Throws 00440 a fatal error if the ModelComponent was started, to avoid 00441 external people messing around with our ModelParam values during 00442 operation of the component. 00443 00444 This function will set the param value for ALL matching model 00445 params found in us (and in our subcomponents, if flags contains 00446 MC_RECURSE). 00447 00448 If the parameter is not found in us (or in any of our 00449 subcomponents, if flags contains MC_RECURSE), this function will 00450 not return (will abort or throw an exception) -- to avoid such 00451 an error, call hasModelParam() first to check that the 00452 particular param exists. 00453 00454 @param name the ModelParam tagname 00455 @param val the parameter value 00456 @param flags bitwise-or'ed combination MC_RECURSE, MC_IGNORE_MISSING */ 00457 template <class T> inline 00458 void setModelParamVal(const std::string& name, const T& val, 00459 const ModelFlag flags = 0); 00460 00461 //! Auxiliary implementation function for setModelParamVal() 00462 void setModelParamValAux(const std::string& name, 00463 const RefHolder& val, 00464 const ModelFlag flags); 00465 00466 //! Get a parameter value 00467 /*! Because the parameter may exist both in us and in several of our 00468 subcomponents, we will stop and return the value of the first 00469 instance encountered, searching first in us, then recursively in 00470 our subcomponents (depth-first search, if flags contains 00471 MC_RECURSE), in the order in which they were added. 00472 00473 If the parameter is not found in us (or in any of our 00474 subcomponents, if flags contains MC_RECURSE), this function will 00475 not return (will abort or throw an exception) -- to avoid such 00476 an error, call hasModelParam() first to check that the 00477 particular param exists. 00478 00479 It is ok to call this on a started ModelComponent. */ 00480 std::string getModelParamString(const std::string& name, 00481 const ModelFlag flags = 0) const; 00482 00483 //! Get a parameter value 00484 /*! This is slow, as it will search for the ModelParam by name. If 00485 you need efficient access to ModelParam values, you should 00486 define a wrapper method in your ModelComponent derivative. In 00487 normal operation, indeed, only the methods of the ModelComponent 00488 derivative should directly access the ModelParam, not external 00489 people. Because the parameter may exist both in us and in 00490 several of our subcomponents, we will stop and return the value 00491 of the first instance encountered, searching first in us, then 00492 recursively in our subcomponents (depth-first search, if flags 00493 contains MC_RECURSE), in the order in which they were added. 00494 00495 If the parameter is not found in us (or in any of our 00496 subcomponents, if flags contains MC_RECURSE), this function will 00497 not return (will abort or throw an exception) -- to avoid such 00498 an error, call hasModelParam() first to check that the 00499 particular param exists. 00500 00501 It is ok to call this on a started ModelComponent. */ 00502 template <class T> inline 00503 T getModelParamVal(const std::string& name, const ModelFlag flags = 0) const; 00504 00505 //! Auxiliary implementation function for getModelParamVal() 00506 void getModelParamValAux(const std::string& name, 00507 RefHolder& val, 00508 const ModelFlag flags) const; 00509 00510 //! External request that one of our ModelParam becomes an option 00511 /*! This is to allow external callers to selectively decide that 00512 some of our internal ModelParam parameters should be exported as 00513 command-line options. If recurse is true, will look for the 00514 ModelParam in all our subcomponents, and will link all matching 00515 ModelParam in us and our subcomponents to the option (so that if a 00516 command-line value is provided, it will affect all matching 00517 ModelParam objects in us and all our subcomponents). Will return 00518 false (and generate a warning message if warn is true) if we (or 00519 our subcomponents if recurse is true) don't have a ModelParam of 00520 the specified name. Will generate a fatal error if we have the 00521 ModelParam but no known command-line option exists for that name 00522 in ModelOptionDefs.C. Returns true if the ModelParam was found and 00523 added as a command-line option. Throws a fatal error is we are 00524 started. */ 00525 bool doRequestOption(const ModelOptionDef* opt, const bool useMyVal = false, 00526 const bool recurse = true, const bool warn = true); 00527 00528 //! External request that we hide a command-line option 00529 /*! In some rare cases (see, e.g., VisualCortexConfigurator), we 00530 want to create a component but avoid exporting some of its 00531 ModelParam members as command-line options. Use with caution, 00532 since the ModelParam still looks and feels like an option, just 00533 the ModelManager will ignore it. This must be called immediately 00534 after construction of the ModelComponent and before 00535 exportOptions() is called (either explicitly or automatically 00536 when the command-line is parsed). Throws a fatal error if 00537 exportOptions() has already been called, we don't have the 00538 option, or we are started. */ 00539 void hideOption(const ModelOptionDef* opt); 00540 00541 //! Return the number of params that we have 00542 size_t getNumModelParams() const; 00543 00544 //! Get non-const access to the i'th model parameter 00545 const ModelParamBase* getModelParam(size_t i) const; 00546 00547 //! Get non-const access to the i'th model parameter 00548 ModelParamBase* getModelParam(size_t i); 00549 00550 //@} 00551 00552 // ###################################################################### 00553 /*! @name ParamMap-based configuration functions */ 00554 //@{ 00555 00556 //! Read params from the ParamMap 00557 /*! Throws a fatal error is we are started. 00558 @param noerr will not generate an error message if some of our 00559 parameters do not exist in ParamMap */ 00560 void readParamsFrom(const ParamMap& pmap, const bool noerr = true); 00561 00562 //! Write params to the ParamMap 00563 /*! Prints out a warning message if we are started. */ 00564 void writeParamsTo(ParamMap& pmap) const; 00565 00566 //@} 00567 00568 // ###################################################################### 00569 /*! @name ParamClient interface */ 00570 //@{ 00571 00572 //! our parameters will register with us upon construction 00573 /*! override of ParamClient's pure virtual function */ 00574 virtual void registerParam(ModelParamBase* mp); 00575 00576 //! Our parameters will register with us upon construction 00577 /*! @param flags Pass USE_MY_VAL here if you want the current value 00578 of the model param to be taken as the new default value, 00579 otherwise pass 0 for flags. */ 00580 virtual void registerOptionedParam(OptionedModelParam* mp, 00581 const ParamFlag flags); 00582 00583 //! our parameters will un-register with us upon destruction 00584 /*! override of ParamClient's pure virtual function */ 00585 virtual void unregisterParam(const ModelParamBase* mp); 00586 00587 //! Called whenever a ModelParamBase has its value changed 00588 /*! Subclasses of ModelComponent should override this function if 00589 they need to do any internal reconfiguration when their 00590 parameters change value (whether due to a command-line option, 00591 or a setModelParamString(), or a readParamsFrom()). See 00592 OrientationChannel::paramChanged() in 00593 Channels/OrientationChannel.C for an example; also see 00594 SaccadeControllerConfigurator::paramChanged() in 00595 Neuro/SaccadeControllers.C for for how to use this to select 00596 subcomponents at runtime. 00597 00598 @param param the address of the ModelParamBase that changed; 00599 subclasses can compare this with the addresses of their 00600 model param members to figure out which is the relevant 00601 param 00602 00603 @param valueChanged true if the value actually changed, false if 00604 the value was "set" but the new value is the same as the 00605 old value; some clients may want to avoid re-doing 00606 expensive operations if the value did not actually change 00607 00608 @param status the subclass that implements paramChanged() should 00609 set *status to CHANGE_REJECTED if it wishes to reject a 00610 particular parameter change; the caller of paramChanged() 00611 is expected to set *status to CHANGE_ACCEPTED prior to 00612 calling paramChanged(), so the implentation of 00613 paramChanged() does not need to set *status 00614 CHANGE_ACCEPTED if it wishes to allow the change since 00615 that will already be the default status 00616 00617 HISTORICAL NOTE: In the past, subclasses would override 00618 setModelParamString() for this same purpose, but in the new 00619 setup, setModelParamString() is NOT virtual and hence should not 00620 be (cannot be) overridden by subclasses. This setup is cleaner 00621 (and potentially more efficient) because subclasses don't have 00622 to compare string names to figure out which param changed; 00623 instead they are passed the address of the param 00624 itself. Furthermore, the new setup is more robust, since we can 00625 handle param value changes that come from any source (e.g., 00626 setModelParamVal(), or ModelParamBase::setValString(), or 00627 OModelParam::setVal()), and not just those that come through 00628 setModelParamString(). 00629 */ 00630 virtual void paramChanged(ModelParamBase* param, 00631 const bool valueChanged, 00632 ParamClient::ChangeStatus* status); 00633 00634 //! Clear our list of command-line options to be exported 00635 void forgetExports(); 00636 00637 //@} 00638 00639 protected: 00640 //! Set our manager. 00641 void setManager(OptionManager& mgr); 00642 00643 //! Check if our options have already been exported. 00644 bool hasBeenExported() const; 00645 00646 //! This is called from within start() before the subcomponents start 00647 virtual void start1(); 00648 00649 //! This is called from within start() after the subcomponents have started 00650 virtual void start2(); 00651 00652 //! This is called from within stop() before the subcomponents stop 00653 virtual void stop1(); 00654 00655 //! This is called from within stop() after the subcomponents have stopped 00656 virtual void stop2(); 00657 00658 //! This is called from within reset() before the subcomponents are reset 00659 virtual void reset1(); 00660 00661 //! This is called from within reset() after the subcomponents are reset 00662 virtual void reset2(); 00663 00664 //! This is called from within save() before the subcomponents save 00665 virtual void save1(const ModelComponentSaveInfo& sinfo); 00666 00667 //! This is called from within save() after the subcomponents have saved 00668 virtual void save2(const ModelComponentSaveInfo& sinfo); 00669 00670 //! Default constructor without arguments. DO NOT USE! 00671 /*! This constructor exists only so that we don't have to explicitly 00672 call the parameterized ModelComponent constructor in each and 00673 every object that has a ModelComponent virtual base somewhere in 00674 its inheritance hierarchy. This constructor, however, will leave 00675 the object uninitialized and you must call init() before you can 00676 use the object. Here is what you should do when building an 00677 inheritance hierarchy that has ModelComponent as virtual base: 1) 00678 in the constructor of the class that virtually derives from 00679 ModelComponent, call init(). See for example Channels/ChannelBase; 00680 2) in classes that concretely derive from the latter one, just 00681 construct as usual; see for example Channels/SingleChannel, 00682 Channels/BlueChannel, etc. */ 00683 ModelComponent(); 00684 00685 //! Make sure you call this if you have used the default constructor 00686 void init(OptionManager& mgr, const std::string& descrName, 00687 const std::string& tagName, const std::string& crealm = "World"); 00688 00689 private: 00690 class Impl; 00691 Impl* const rep; 00692 }; 00693 00694 // ###################################################################### 00695 // #################### INLINED METHODS: 00696 // ###################################################################### 00697 00698 template <class T> inline 00699 void ModelComponent::setModelParamVal(const std::string& name, 00700 const T& val, 00701 const ModelFlag flags) 00702 { 00703 TRefHolder<const T> ref(val); 00704 return setModelParamValAux(name, ref, flags); 00705 } 00706 00707 // ###################################################################### 00708 template <class T> inline 00709 T ModelComponent::getModelParamVal(const std::string& name, 00710 const ModelFlag flags) const 00711 { 00712 T val; 00713 TRefHolder<T> ref(val); 00714 getModelParamValAux(name, ref, flags); 00715 return val; 00716 } 00717 00718 #endif 00719 00720 // ###################################################################### 00721 /* So things look consistent in everyone's emacs... */ 00722 /* Local Variables: */ 00723 /* indent-tabs-mode: nil */ 00724 /* End: */