00001 /*!@file Component/ModelParam.H A template ModelComponent parameter class */ 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/ModelParam.H $ 00035 // $Id: ModelParam.H 8782 2007-09-20 22:34:54Z rjpeters $ 00036 // 00037 00038 #ifndef MODELPARAM_H_DEFINED 00039 #define MODELPARAM_H_DEFINED 00040 00041 #include "Component/ModelParamBase.H" 00042 #include "Component/ParamClient.H" 00043 #include "Component/ParamFlags.H" 00044 #include "Util/StringConversions.H" 00045 #include "rutz/fileposition.h" // for SRC_POS 00046 #include "rutz/mutex.h" 00047 #include "rutz/shared_ptr.h" 00048 #include "rutz/stderror.h" // for rutz::throw_bad_cast() 00049 00050 #include <iosfwd> 00051 #include <string> 00052 #include <typeinfo> 00053 00054 #include <pthread.h> 00055 00056 class ModelOptionDef; 00057 class ParamMap; 00058 00059 // ###################################################################### 00060 //! Helper implementation class for NModelParam and OModelParam 00061 class ModelParamAuxImpl 00062 { 00063 public: 00064 //! Construct from a ModelOptionDef* 00065 /*! This model param will get its name from the ModelOptionDef*. 00066 00067 @param self pointer to the object that is using this impl 00068 @param client the ParamClient we are attached to 00069 @param nam the name of the TModelParamBase, that will be used to 00070 store its value in a ParamMap and fetch command-line option 00071 configuration data. 00072 @param flags can be set to USE_MY_VAL in order to take this 00073 param's value as the new default value, otherwise pass 0 for flags 00074 @param valtype the typeid of the parameter; we will check to 00075 make sure this matches the typeid declared by the 00076 ModelOptionDef 00077 */ 00078 ModelParamAuxImpl(OptionedModelParam* self, 00079 const ModelOptionDef* def, 00080 ParamClient* client, 00081 const ParamFlag flags, 00082 const std::type_info& valtype); 00083 00084 //! Construct with a string name only 00085 /*! This model param will NOT be associated with any ModelOptionDef 00086 -- to get that, use the other constructor that takes a 00087 ModelOptionDef* instead of a name. 00088 00089 @param self pointer to the object that is using this impl 00090 @param client the ParamClient we are attached to 00091 @param nam the name of the ModelParamAuxImpl, that will be used to 00092 store its value in a ParamMap and fetch command-line option 00093 configuration data. */ 00094 ModelParamAuxImpl(ModelParamBase* self, 00095 const std::string& nam, ParamClient* client); 00096 00097 //! Destructor 00098 ~ModelParamAuxImpl(); 00099 00100 //! get the ModelParamAuxImpl's name 00101 std::string getName() const; 00102 00103 //! get the associated option def 00104 const ModelOptionDef* getOptionDef() const; 00105 00106 //! Print out our name and contents, mostly for debugging 00107 void printout(std::ostream& s, const std::string& prefix) const; 00108 00109 //! Write parameter value to ParamMap 00110 void writeTo(ParamMap& pmap) const; 00111 00112 //! Get parameter value from ParamMap 00113 /*! @param noerr will not generate an error message if the parameter 00114 does not exist in ParamMap. */ 00115 void readFrom(const ParamMap& pmap, const bool noerr); 00116 00117 //! Call paramChanged() on our client 00118 ParamClient::ChangeStatus sendChangedMessage(bool didchange); 00119 00120 //! Convenience function to retrieve def->defval. 00121 /*! The reason we have this here is so that we don't have to 00122 #include ModelOptionDef.H from this widely-used header file. */ 00123 static const char* defaultValueOf(const ModelOptionDef* def); 00124 00125 //! Get a mutex for locking the parameter value for reading 00126 /*! We only return an actual mutex if we were passed 00127 ALLOW_ONLINE_CHANGES in our constructor (i.e., 00128 ModelParamBase::allowsOnlineChanges() returns true); that's 00129 because we assume that if online parameter changes are disabled, 00130 then there is no need for between-thread synchronization of our 00131 parameter value. 00132 00133 The returned mutex, if non-null, will be a recursive mutex so 00134 that we can allow reentrant calls to getVal() from within a 00135 setVal() in the same thread, while still blocking getVal() calls 00136 from other threads during a setVal() call. 00137 */ 00138 pthread_mutex_t* readLock() const 00139 { return itsLocks ? &itsLocks[READLOCK] : 0; } 00140 00141 //! Get a mutex for locking the parameter value for writing 00142 /*! We only return an actual mutex if we were passed 00143 ALLOW_ONLINE_CHANGES in our constructor (i.e., 00144 ModelParamBase::allowsOnlineChanges() returns true); that's 00145 because we assume that if online parameter changes are disabled, 00146 then there is no need for between-thread synchronization of our 00147 parameter value. 00148 00149 The returned mutex, if non-null, will be an error-checking mutex 00150 so that we can detect attempts to acquire the lock more than 00151 once from within the same thread. These attempts would represent 00152 reentrant setVal() calls, such as when setVal() triggers a 00153 paramChanged() call that in turn triggers another setVal() of 00154 the same parameter (which is forbidden by design). 00155 */ 00156 pthread_mutex_t* writeLock() const 00157 { return itsLocks ? &itsLocks[WRITELOCK] : 0; } 00158 00159 private: 00160 // Yes, there is no parameter value data proper and no way to get 00161 // the parameter value directly! This is only a helper class. The 00162 // NModelParam and OModelParam classes provide concrete paramter 00163 // values. 00164 00165 //! indices into the optional 2-element itsLocks array 00166 enum { READLOCK = 0, WRITELOCK = 1 }; 00167 00168 ModelParamBase* const itsSelf; //!< our owner 00169 ParamClient* const itsClient; //!< keep track of our client 00170 ModelOptionDef const* const itsOption; //!< may be null 00171 std::string const itsName; //!< the parameter name as used in ParamMap 00172 pthread_mutex_t* const itsLocks; //!< optional 2-element array of {read,write} locks for getVal()/setVal() 00173 bool itsInCallback; //!< whether we're currently doing a paramChanged() callback 00174 00175 ModelParamAuxImpl(const ModelParamAuxImpl& m); //!< forbid copy-contruction 00176 ModelParamAuxImpl& operator=(const ModelParamAuxImpl& m); //!< forbid copy 00177 }; 00178 00179 // ###################################################################### 00180 //! Helper class to provide transactional semantics for a value change 00181 /*! The provisionally assigns a new value to a variable, but upon 00182 destruction (e.g. at block exit), the original value is restored 00183 unless the transaction has been explicitly accepted. */ 00184 template <class T> 00185 class ValueChangeTransaction 00186 { 00187 public: 00188 ValueChangeTransaction(T* p, const T& newval) 00189 : oldval(*p), var(p), accepted(false) 00190 { 00191 *var = newval; 00192 } 00193 00194 ~ValueChangeTransaction() 00195 { 00196 if (!accepted) 00197 // Note, if this destructor is triggered because of exception 00198 // propagation, and the *var=oldval assignment also causes an 00199 // exception, then we will crash with std::terminate(). In 00200 // practice, this shouldn't be much of a problem since 00201 // operator=() should generally be exception-free for the kinds 00202 // of types that are held in model params. 00203 *var = oldval; 00204 } 00205 00206 void acceptChange() { accepted = true; } 00207 00208 private: 00209 T const oldval; 00210 T* const var; 00211 bool accepted; 00212 }; 00213 00214 // ###################################################################### 00215 //! A class for params of type T that don't have command-line options 00216 /*! NModelParam delegates its implementation to 00217 ModelParamAuxImpl. NModelParam<T> offers getVal() and setVal() for 00218 direct access to the T value. 00219 00220 Note that the implementation is entirely inline so that we don't 00221 have to explicitly instantiate NModelParam<T> anywhere; plus these 00222 functions are small so any compile time hit from having the 00223 functions inline is small. 00224 00225 Note that we have two similar template types: NModelParam and 00226 OModelParam. The 'O' is for "command-line Option", and the 'N' is 00227 for "Not a command-line option". NModelParam only implements 00228 ModelParamBase and is constructed with a string for its parameter 00229 name. On the other hand, OModelParam implements 00230 OptionedModelParam, which means that it offers getOptionDef(), and 00231 it takes a ModelOptionDef* in its constructor instead of a string 00232 (the parameter name is taken from the ModelOptionDef). 00233 */ 00234 template <class T> class NModelParam : public ModelParamBase 00235 { 00236 public: 00237 // ###################################################################### 00238 /*! @name Constructors and Destructors */ 00239 //@{ 00240 00241 //! Construct with a string name only 00242 /*! Same as ModelParamAuxImpl plus an initial parameter value 00243 00244 @param flags If flags contains ALLOW_ONLINE_CHANGES, then this 00245 param will be marked as being able to be changed while the model 00246 is active. 00247 */ 00248 inline NModelParam(const std::string& nam, ParamClient* client, 00249 const T& initval, const ParamFlag flags = 0); 00250 00251 //! A "pseudo-constructor" that makes a rutz::shared_ptr<NModelParam>. 00252 /*! This can be used in places that need arrays of NModelParam 00253 objects. Since NModelParam doesn't have a default constructor, we 00254 can't make an array of NModelParam objects. But we can make an 00255 array of rutz::shared_ptr<NModelParam> objects. Then we can initialize 00256 each in a loop by doing arr[i] = NModelParam<T>::make(...). 00257 00258 Note that an alternative to C-style arrays (where the type must 00259 have a default constructor) is to use std::vector. Then we can 00260 do vec.push_back(NModelParam<T>(...)) and build the vector 00261 incrementally, again without needed a default constructor. 00262 00263 Historical note: this substitutes for the previous strategy of 00264 giving NModelParam a default constructor plus an init() method 00265 that would be called in the array-initialization loop like 00266 arr[i].init(...), plus an initialized() methed. The current 00267 approach avoids the need for either init() or initialized(), 00268 instead we can let rutz::shared_ptr worry about whether the object is 00269 initialized -- we can test rutz::shared_ptr<NModelParam<T>>::get() != 0 00270 to see if the param is initialized. 00271 */ 00272 static inline rutz::shared_ptr<NModelParam<T> > 00273 make(const std::string& nam, ParamClient* client, const T& initval, 00274 const ParamFlag flags = 0) 00275 { return rutz::shared_ptr<NModelParam<T> >(new NModelParam<T>(nam, client, initval, flags)); } 00276 00277 //@} 00278 00279 // ###################################################################### 00280 /*! @name Access functions */ 00281 //@{ 00282 00283 //! get the ModelParamAuxImpl's name 00284 virtual std::string getName() const 00285 { return impl.getName(); } 00286 00287 //! Get the value 00288 /*! Note that there is no non-const function to get a non-const 00289 reference; that's because if we handed out a non-const reference 00290 then we'd have no way to know if callers changed the value, and 00291 we wouldn't be able to properly trigger paramChanged() on our 00292 ParamClient. Thus if you need to change the value, you should 00293 call getVal() to get a copy of the value, then do your 00294 modifications, then apply those changes with setVal(), which 00295 will trigger a paramChanged(). */ 00296 T getVal() const 00297 { 00298 GVX_MUTEX_LOCK(impl.readLock()); 00299 return this->val; 00300 } 00301 00302 //! Set the value 00303 /*! @return true if the change succeeded; false otherwise. */ 00304 bool setVal(const T& v) 00305 { 00306 // acquire a write lock for the entire duration of the setVal() 00307 // call, so that no other clients can enter setVal() concurrently; 00308 // in addition, since the write lock is an error-checking mutex, 00309 // we will get an error if setVal() is called recursively from 00310 // within the same thread such that a deadlock would otherwise 00311 // occur 00312 GVX_MUTEX_LOCK(impl.writeLock()); 00313 00314 // acquire a read lock to block out readers in other threads while 00315 // we update this->val (this is a recursive lock so we only block 00316 // out other threads but don't block ourselves from calling 00317 // getVal() from within the sendChangedMessage() call): 00318 GVX_MUTEX_LOCK(impl.readLock()); 00319 00320 const bool didchange = !(this->val == v); 00321 ValueChangeTransaction<T> tx(&this->val, v); 00322 00323 if (ParamClient::CHANGE_REJECTED 00324 != impl.sendChangedMessage(didchange)) 00325 { 00326 tx.acceptChange(); 00327 return true; 00328 } 00329 return false; 00330 } 00331 00332 //! Get the value as a string 00333 virtual std::string getValString() const 00334 { 00335 return convertToString(this->getVal()); 00336 } 00337 00338 //! Set the parameter value from a textual representation, notify clients of the change 00339 /*! @return true if the change succeeded; false otherwise. */ 00340 virtual bool setValString(const std::string& textval) 00341 { 00342 T newval; 00343 convertFromString(textval, newval); 00344 // don't update this->val until after we are sure that the 00345 // convertFromString() has succeeded; that way if 00346 // convertFromString() fails we won't end up with a partially 00347 // modified or garbled value in this->val 00348 return this->setVal(newval); 00349 } 00350 00351 //! Get the current value through a dynamically-typed RefHolder. 00352 inline virtual void getValGeneric(RefHolder& ref) const; 00353 00354 //! Set the current value through a dynamically-typed RefHolder. 00355 /*! @return true if the change succeeded; false otherwise. */ 00356 inline virtual bool setValGeneric(const RefHolder& ref); 00357 00358 //@} 00359 00360 00361 // ###################################################################### 00362 /*! @name Input/Output functions */ 00363 //@{ 00364 00365 //! Print out our name and contents, mostly for debugging 00366 virtual void printout(std::ostream& s, 00367 const std::string& prefix = "") const 00368 { impl.printout(s, prefix); } 00369 00370 //! Write parameter value to ParamMap 00371 virtual void writeTo(ParamMap& pmap) const 00372 { impl.writeTo(pmap); } 00373 00374 //! Get parameter value from ParamMap 00375 /*! @param noerr will not generate an error message if the parameter 00376 does not exist in ParamMap. */ 00377 virtual void readFrom(const ParamMap& pmap, 00378 const bool noerr = true) 00379 { impl.readFrom(pmap, noerr); } 00380 00381 //@} 00382 00383 private: 00384 ModelParamAuxImpl impl; 00385 T val; // the parameter value 00386 NModelParam(const NModelParam<T>& m); //!< forbid copy-contruction 00387 NModelParam& operator=(const NModelParam<T>& m); //!< forbid copy 00388 }; 00389 00390 00391 00392 // ###################################################################### 00393 //! A class for params of type T that have a command-line option 00394 /*! OModelParam is just like NModelParam except that it offers 00395 getOptionDef() and takes a ModelOptionDef* in its constructor. See 00396 the NModelParam documentation for all other details. 00397 */ 00398 template <class T> class OModelParam : public OptionedModelParam 00399 { 00400 public: 00401 // ###################################################################### 00402 /*! @name Constructors and Destructors 00403 00404 see NModelParam for more details 00405 */ 00406 //@{ 00407 00408 //! Construct, using the initial value from a ModelOptionDef 00409 /*! If you want to specify a different initial value, use the other 00410 constructor which takes an initial value plus a USE_MY_VAL flag. 00411 00412 @param flags If flags contains ALLOW_ONLINE_CHANGES, then this 00413 param will be marked as being able to be changed while the model 00414 is active. 00415 */ 00416 inline OModelParam(const ModelOptionDef* def, ParamClient* client, 00417 const ParamFlag flags = 0); 00418 00419 //! Construct, using a specified initial value 00420 /*! @param flags If flags contains USE_MY_VAL, then the given 00421 initval will be pushed into the OptionManager as the new default 00422 value for the given ModelOptionDef. If you just want to take the 00423 existing default value from the ModelOptionDef as the initial 00424 value for this OModelParam, then use the other constructor that 00425 doesn't take an initval parameter. If flags contains 00426 ALLOW_ONLINE_CHANGES, then this param will be marked as being 00427 able to be changed while the model is active. */ 00428 inline OModelParam(const ModelOptionDef* def, ParamClient* client, 00429 const T& initval, const ParamFlag flags); 00430 00431 //! A "pseudo-constructor" that makes a rutz::shared_ptr<OModelParam>. 00432 static inline rutz::shared_ptr<OModelParam<T> > 00433 make(const ModelOptionDef* def, ParamClient* client, 00434 const ParamFlag flags = 0) 00435 { 00436 return rutz::shared_ptr<OModelParam<T> > (new OModelParam<T>(def, client, flags)); 00437 } 00438 00439 //! A "pseudo-constructor" that makes a rutz::shared_ptr<OModelParam>. 00440 static inline rutz::shared_ptr<OModelParam<T> > 00441 make(const ModelOptionDef* def, ParamClient* client, 00442 const T& initval, const ParamFlag flags) 00443 { 00444 return rutz::shared_ptr<OModelParam<T> > 00445 (new OModelParam<T>(def, client, initval, flags)); 00446 } 00447 00448 //@} 00449 00450 // ###################################################################### 00451 /*! @name Access functions 00452 00453 see NModelParam for more details 00454 */ 00455 //@{ 00456 00457 //! get the ModelParamAuxImpl's name 00458 virtual std::string getName() const 00459 { return impl.getName(); } 00460 00461 //! get the associated option def 00462 virtual const ModelOptionDef* getOptionDef() const 00463 { return impl.getOptionDef(); } 00464 00465 //! Get the value 00466 /*! Note that there is no non-const function to get a non-const 00467 reference; that's because if we handed out a non-const reference 00468 then we'd have no way to know if callers changed the value, and 00469 we wouldn't be able to properly trigger paramChanged() on our 00470 ParamClient. Thus if you need to change the value, you should 00471 call getVal() to get a copy of the value, then do your 00472 modifications, then apply those changes with setVal(), which 00473 will trigger a paramChanged(). */ 00474 T getVal() const 00475 { 00476 GVX_MUTEX_LOCK(impl.readLock()); 00477 return this->val; 00478 } 00479 00480 //! Set the value 00481 /*! @return true if the change succeeded; false otherwise. */ 00482 bool setVal(const T& v) 00483 { 00484 // acquire a write lock for the entire duration of the setVal() 00485 // call, so that no other clients can enter setVal() concurrently; 00486 // in addition, since the write lock is an error-checking mutex, 00487 // we will get an error if setVal() is called recursively from 00488 // within the same thread such that a deadlock would otherwise 00489 // occur 00490 GVX_MUTEX_LOCK(impl.writeLock()); 00491 00492 // acquire a read lock to block out readers in other threads while 00493 // we update this->val (this is a recursive lock so we only block 00494 // out other threads but don't block ourselves from calling 00495 // getVal() from within the sendChangedMessage() call): 00496 GVX_MUTEX_LOCK(impl.readLock()); 00497 00498 const bool didchange = !(this->val == v); 00499 ValueChangeTransaction<T> tx(&this->val, v); 00500 00501 if (ParamClient::CHANGE_REJECTED 00502 != impl.sendChangedMessage(didchange)) 00503 { 00504 tx.acceptChange(); 00505 return true; 00506 } 00507 return false; 00508 } 00509 00510 //! Get the value as a string 00511 virtual std::string getValString() const 00512 { 00513 return convertToString(this->getVal()); 00514 } 00515 00516 //! Set the parameter value from a textual representation, notify clients of the change 00517 /*! @return true if the change succeeded; false otherwise. */ 00518 virtual bool setValString(const std::string& textval) 00519 { 00520 T newval; 00521 convertFromString(textval, newval); 00522 // don't update this->val until after we are sure that the 00523 // convertFromString() has succeeded; that way if 00524 // convertFromString() fails we won't end up with a partially 00525 // modified or garbled value in this->val 00526 return this->setVal(newval); 00527 } 00528 00529 //! Get the current value through a dynamically-typed RefHolder. 00530 inline virtual void getValGeneric(RefHolder& ref) const; 00531 00532 //! Set the current value through a dynamically-typed RefHolder. 00533 /*! @return true if the change succeeded; false otherwise. */ 00534 inline virtual bool setValGeneric(const RefHolder& ref); 00535 00536 //@} 00537 00538 00539 // ###################################################################### 00540 /*! @name Input/Output functions 00541 00542 see NModelParam for more details 00543 */ 00544 //@{ 00545 00546 //! Print out our name and contents, mostly for debugging 00547 virtual void printout(std::ostream& s, 00548 const std::string& prefix = "") const 00549 { impl.printout(s, prefix); } 00550 00551 //! Write parameter value to ParamMap 00552 virtual void writeTo(ParamMap& pmap) const 00553 { impl.writeTo(pmap); } 00554 00555 //! Get parameter value from ParamMap 00556 virtual void readFrom(const ParamMap& pmap, 00557 const bool noerr = true) 00558 { impl.readFrom(pmap, noerr); } 00559 00560 //@} 00561 00562 private: 00563 ModelParamAuxImpl impl; 00564 T val; // the parameter value 00565 OModelParam(const OModelParam<T>& m); //!< forbid copy-contruction 00566 OModelParam& operator=(const OModelParam<T>& m); //!< forbid copy 00567 }; 00568 00569 00570 00571 // ###################################################################### 00572 // ############# NModelParam<T> implementation 00573 // ###################################################################### 00574 00575 // ###################################################################### 00576 template <class T> inline 00577 NModelParam<T>::NModelParam(const std::string& nam, 00578 ParamClient* client, 00579 const T& initval, 00580 const ParamFlag flags) : 00581 ModelParamBase(flags), 00582 impl(this, nam, client), 00583 val(initval) 00584 {} 00585 00586 // ###################################################################### 00587 template <class T> inline 00588 void NModelParam<T>::getValGeneric(RefHolder& ref) const 00589 { 00590 typedef TRefHolder<T> reftype; 00591 reftype* tref = dynamic_cast<reftype*>(&ref); 00592 if (tref == 0) 00593 rutz::throw_bad_cast(typeid(T), ref.type(), SRC_POS); 00594 tref->ref = this->getVal(); 00595 } 00596 00597 // ###################################################################### 00598 template <class T> inline 00599 bool NModelParam<T>::setValGeneric(const RefHolder& ref) 00600 { 00601 typedef TRefHolder<const T> reftype; 00602 const reftype* tref = dynamic_cast<const reftype*>(&ref); 00603 if (tref == 0) 00604 rutz::throw_bad_cast(typeid(T), ref.type(), SRC_POS); 00605 return this->setVal(tref->ref); 00606 } 00607 00608 00609 // ###################################################################### 00610 // ############# OModelParam<T> implementation 00611 // ###################################################################### 00612 00613 // ###################################################################### 00614 template <class T> inline 00615 OModelParam<T>::OModelParam(const ModelOptionDef* def, 00616 ParamClient* client, 00617 const ParamFlag flags) : 00618 OptionedModelParam(flags), 00619 impl(this, def, client, /*flags*/ 0, typeid(T)), 00620 val(fromStr<T>(ModelParamAuxImpl::defaultValueOf(def))) 00621 {} 00622 00623 // ###################################################################### 00624 template <class T> inline 00625 OModelParam<T>::OModelParam(const ModelOptionDef* def, 00626 ParamClient* client, 00627 const T& initval, 00628 const int flags) : 00629 OptionedModelParam(flags), 00630 impl(this, def, client, flags, typeid(T)), 00631 val(initval) 00632 {} 00633 00634 // ###################################################################### 00635 template <class T> inline 00636 void OModelParam<T>::getValGeneric(RefHolder& ref) const 00637 { 00638 typedef TRefHolder<T> reftype; 00639 reftype* tref = dynamic_cast<reftype*>(&ref); 00640 if (tref == 0) 00641 rutz::throw_bad_cast(typeid(T), ref.type(), SRC_POS); 00642 tref->ref = this->getVal(); 00643 } 00644 00645 // ###################################################################### 00646 template <class T> inline 00647 bool OModelParam<T>::setValGeneric(const RefHolder& ref) 00648 { 00649 typedef TRefHolder<const T> reftype; 00650 const reftype* tref = dynamic_cast<const reftype*>(&ref); 00651 if (tref == 0) 00652 rutz::throw_bad_cast(typeid(T), ref.type(), SRC_POS); 00653 return this->setVal(tref->ref); 00654 } 00655 00656 #endif 00657 00658 // ###################################################################### 00659 /* So things look consistent in everyone's emacs... */ 00660 /* Local Variables: */ 00661 /* indent-tabs-mode: nil */ 00662 /* End: */