00001 /*!@file Component/ModelComponent.C 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.C $ 00035 // $Id: ModelComponent.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 #include "Component/ModelComponent.H" 00039 00040 #include "Component/ModelOptionDef.H" 00041 #include "Component/OptionManager.H" 00042 #include "Component/ParamMap.H" 00043 #include "Util/Assert.H" 00044 #include "Util/log.H" 00045 #include "rutz/error_context.h" 00046 #include "rutz/sfmt.h" 00047 #include "rutz/shared_ptr.h" 00048 00049 #include <exception> 00050 #include <list> 00051 #include <pthread.h> 00052 #include <set> 00053 #include <vector> 00054 00055 namespace dummy_namespace_to_avoid_gcc411_bug_ModelComponent_C 00056 { 00057 struct ParamInfo; 00058 00059 // NOTE! It is often NOT safe to iterate over a PinfoList with 00060 // iterators in the ModelComponent implementation, because often we 00061 // end up modifying the PinfoList (rep->pinfos) indirectly as a 00062 // result of the code in the loop body -- when that happens, 00063 // iterators are likely to be invalidated and so continuing the loop 00064 // will result in a crash. Thus it is necessary to iterate over 00065 // PinfoList using array indexes and a live test against 00066 // rep->pinfos.size() at each loop iteration to guard against online 00067 // changes to rep->pinfos itself. 00068 typedef std::vector<ParamInfo> PinfoList; 00069 00070 typedef std::vector< nub::ref<ModelComponent> > SubCompVec; 00071 00072 /// Helper class to keep track of possibly-exported command-line options 00073 struct ParamInfo 00074 { 00075 ParamInfo(ModelComponent* c, ModelParamBase* mp) 00076 : client(c), param(mp), oparam(0), exportMe(false), useMyVal(false) {} 00077 00078 ParamInfo(ModelComponent* c, OptionedModelParam* omp, bool useme) 00079 : client(c), param(omp), oparam(omp), exportMe(true), useMyVal(useme) {} 00080 00081 ModelComponent* client; 00082 ModelParamBase* param; 00083 OptionedModelParam* oparam; 00084 bool exportMe; 00085 bool useMyVal; 00086 }; 00087 00088 /// Helper class to ensure that no one tries to do rutz::shared_ptr<ModelComponent>. 00089 /** Since ModelComponent derives from nub::object, its 00090 reference-count is handled internally and should be managed by 00091 nub::ref or nub::soft_ref smart pointers. Catastrophe would be 00092 the result if we ended up with both a nub::soft_ref and a 00093 rutz::shared_ptr to the same object. So, to avoid that, we use the 00094 following solution: rutz::shared_ptr offers to call a hook function 00095 everytime somebody tries to construct a rutz::shared_ptr, and we here 00096 install such a hook function that checks to see if we recognize 00097 the attempted rutz::shared_ptr address as a live ModelComponent 00098 object. If so, we issue an LFATAL(). */ 00099 struct PtrChecker 00100 { 00101 typedef std::set<const void*> ComponentSet; 00102 00103 ComponentSet itsSet; 00104 00105 void addPtr(const void* p) { itsSet.insert(p); } 00106 bool hasPtr(const void* p) const { return itsSet.find(p) != itsSet.end(); } 00107 void forgetPtr(const void* p) { itsSet.erase(p); } 00108 }; 00109 00110 // we actually want to "leak" this pointer, so that the object it 00111 // points to never gets deleted... that's because we're going to be 00112 // using the PtrChecker object in ~ModelComponent(), and if the 00113 // PtrChecker gets destroyed before some final call to 00114 // ~ModelComponent() (e.g., likely to be ~ModelManager() that gets 00115 // called last) then we'll get some crash 00116 PtrChecker* g_checker = 0; 00117 00118 PtrChecker& getChecker() 00119 { 00120 ASSERT(g_checker != 0); 00121 return *g_checker; 00122 } 00123 00124 /// Here is the hook function itself. 00125 /** This hook function is registered with rutz::shared_ptr by 00126 ModelComponent::Impl() when Impl() is called the first time. */ 00127 void checkNoSuchComponent(const void* p) 00128 { 00129 if (getChecker().hasPtr(p)) 00130 LFATAL("\n\tLooks like you were trying to construct a\n" 00131 "\trutz::shared_ptr<ModelComponent> (or some derivative of\n" 00132 "\tModelComponent) -- but instead you should use\n" 00133 "\tnub::ref<ModelComponent>."); 00134 } 00135 00136 pthread_once_t checker_init_once = PTHREAD_ONCE_INIT; 00137 void checker_init() 00138 { 00139 ASSERT(g_checker == 0); 00140 g_checker = new PtrChecker; 00141 rutz::shared_ptr_aux::set_check_function(&checkNoSuchComponent); 00142 } 00143 } 00144 00145 using namespace dummy_namespace_to_avoid_gcc411_bug_ModelComponent_C; 00146 00147 // ###################################################################### 00148 // ###################################################################### 00149 // ModelComponent::Impl member functions 00150 // ###################################################################### 00151 // ###################################################################### 00152 00153 //! Private "pimpl" implementation class for ModelComponent 00154 struct ModelComponent::Impl 00155 { 00156 Impl(OptionManager* manager, 00157 const std::string& descrName, 00158 const std::string& tag, 00159 const std::string& crealm) 00160 : 00161 mgr(manager), 00162 dname(descrName), 00163 tname(tag), 00164 realm(crealm), 00165 started(false), 00166 hasBeenExported(false), 00167 parent() 00168 { 00169 pthread_once(&checker_init_once, &checker_init); 00170 } 00171 00172 // add a new ParamInfo, but only if we don't already have the same one 00173 void addParam(const ParamInfo& pinfo) 00174 { 00175 // check to see if we already have this param in our list 00176 for (size_t i = 0; i < this->pinfos.size(); ++i) 00177 if (this->pinfos[i].param == pinfo.param) 00178 { 00179 // this can't be an LFATAL() because there is at least one 00180 // place (Beowulf/Beowulf.C) where the same param 00181 // (itsSlaveNames) can be registered/unregistered multiple 00182 // times, and it's difficult to ensure that it would never 00183 // be registered twice in a row 00184 LERROR("duplicate attempt to add a model param (%s)" 00185 " -- old info overwritten", 00186 pinfo.param->getName().c_str()); 00187 00188 // overwrite the old info so we avoid having duplicate 00189 // records in pinfos: 00190 this->pinfos[i] = pinfo; 00191 return; 00192 } 00193 00194 // ok, we haven't seen this param before, so just add it to the 00195 // end of our list: 00196 this->pinfos.push_back(pinfo); 00197 } 00198 00199 void findMatchingParams(const std::string& name, 00200 const ModelFlag flags, 00201 std::vector<ParamInfo>& matches) const 00202 { 00203 // first look in our own params: 00204 for (size_t i = 0; i < this->pinfos.size(); ++i) 00205 if (name.compare(this->pinfos[i].param->getName()) == 0) 00206 matches.push_back(this->pinfos[i]); 00207 00208 // now check the subcomps: 00209 if (flags & MC_RECURSE) 00210 for (SubCompVec::const_iterator citr = this->subComps.begin(); 00211 citr != this->subComps.end(); 00212 ++citr) 00213 (*citr)->rep->findMatchingParams(name, 00214 flags | MC_IGNORE_MISSING, 00215 matches); 00216 00217 // now see if the caller wanted to treat an empty result as an error: 00218 if (matches.size() == 0 && !(flags & MC_IGNORE_MISSING)) 00219 LFATAL("No parameter named '%s'", name.c_str()); 00220 } 00221 00222 OptionManager* mgr; //<! our manager 00223 std::string dname; //<! descriptive name 00224 std::string tname; //<! tag name 00225 std::string realm; //<! our realm 00226 bool started; //<! did we start()? 00227 PinfoList pinfos; //<! our model parameters 00228 SubCompVec subComps; //<! our sub-components 00229 bool hasBeenExported; //<! did we exportOptions()? 00230 nub::soft_ref<ModelComponent> parent; //<! our parent object, or null 00231 00232 private: 00233 Impl(const Impl&); // not implemented 00234 Impl& operator=(const Impl&); // not implemented 00235 }; 00236 00237 // ###################################################################### 00238 // ###################################################################### 00239 // ModelComponent member functions 00240 // ###################################################################### 00241 // ###################################################################### 00242 00243 // ###################################################################### 00244 ModelComponent::ModelComponent(OptionManager& mgr, 00245 const std::string& descrName, 00246 const std::string& tag, 00247 const std::string& crealm) : 00248 rep(new Impl(&mgr, descrName, tag, crealm)) 00249 { 00250 CLDEBUG(">>>> Constructed <<<<"); 00251 00252 getChecker().addPtr(rutz::full_object_cast(this)); 00253 } 00254 00255 // ###################################################################### 00256 ModelComponent::ModelComponent(const std::string& descrName, 00257 const std::string& tag, 00258 const std::string& crealm) : 00259 rep(new Impl(0, descrName, tag, crealm)) 00260 { 00261 getChecker().addPtr(rutz::full_object_cast(this)); 00262 } 00263 00264 // ###################################################################### 00265 ModelComponent::ModelComponent() : 00266 rep(new Impl(0, "BUG!", "BUG!", "World")) 00267 { 00268 //LERROR( 00269 // "\n\n##########\n" 00270 // "Oh No! You probably forgot to include a call to the\n" 00271 // "ModelComponent constructor in some class' initialization list.\n" 00272 // "##########\n" 00273 // ); 00274 } 00275 00276 // ###################################################################### 00277 void ModelComponent::init(OptionManager& mgr, const std::string& descrName, 00278 const std::string& tagName, const std::string& crealm) 00279 { 00280 rep->mgr = &mgr; 00281 rep->dname = descrName; 00282 rep->tname = tagName; 00283 rep->realm = crealm; 00284 } 00285 00286 // ###################################################################### 00287 ModelComponent::~ModelComponent() 00288 { 00289 getChecker().forgetPtr(rutz::full_object_cast(this)); 00290 00291 CLDEBUG(">>>> Destroying..."); 00292 00293 // stop ourselves if necessary: 00294 if (rep->started) stop(); 00295 00296 // strictly speaking these calls aren't necessary since the vectors 00297 // will be destroyed anyway during "delete rep"; but if we call them 00298 // here then it is easier for us to trace the destruction of 00299 // subcomponents within our ">>>> Destroying"/"<<<< Destroyed" calls 00300 rep->subComps.clear(); 00301 rep->pinfos.clear(); 00302 00303 CLDEBUG("<<<< Destroyed"); 00304 00305 delete rep; 00306 } 00307 00308 // ###################################################################### 00309 void ModelComponent::start() 00310 { 00311 if (rep->started) 00312 CLFATAL("ModelComponent '%s' already started", rep->dname.c_str()); 00313 00314 if (rep->mgr == 0) 00315 CLFATAL("I need an OptionManager!"); 00316 00317 if (!rep->hasBeenExported) 00318 // If exportOptions() isn't called on us, then our OModelParams 00319 // won't be hooked up to their command-line options and won't have 00320 // the correct values. This is normally not a problem for objects 00321 // that are created in main() prior to command-line parsing, 00322 // because exportOptions() is called recursively inside 00323 // ModelManager::parseCommandLine(). However, failure to 00324 // exportOptions() is a likely problem with ModelComponent child 00325 // objects that are created in a paramChanged() callback during 00326 // command-line parsing as a result of some command-line option 00327 // that has been seen; the owner of that object needs be sure to 00328 // call exportOptions(MC_RECURSE) on that newly-created object. 00329 CLFATAL("Oops; I need to have exportOptions() called on me " 00330 "before I am started"); 00331 00332 GVX_ERR_CONTEXT(rutz::sfmt("starting %s '%s'", 00333 this->obj_typename().c_str(), 00334 this->tagName().c_str())); 00335 00336 CLDEBUG(">>>> Starting..."); 00337 00338 // do our startup that is before our subs have been started: 00339 this->start1(); 00340 00341 // keep track of which subcomponents have been started, so that if 00342 // we get any exceptions, we can stop() those subcomponents 00343 SubCompVec started_comps; 00344 00345 try 00346 { 00347 // start our subcomponents in order of addition: 00348 SubCompVec::iterator citr = rep->subComps.begin(); 00349 while (citr != rep->subComps.end()) 00350 { 00351 (*citr)->start(); 00352 started_comps.push_back(*citr); 00353 ++citr; 00354 } 00355 00356 // do our startup that is after our subs have been started: 00357 this->start2(); 00358 00359 // we are started: 00360 rep->started = true; 00361 CLDEBUG("<<<< Started"); 00362 } 00363 catch (...) 00364 { 00365 // ok, one of our subcomponents threw an exception during its 00366 // start(), so give any subcomponents that were already 00367 // start()-ed a chance to clean up by calling stop on them, 00368 // before we allow the exception to propagate 00369 while (started_comps.size() > 0) 00370 { 00371 // since stop() is analogous to destructors, we enforce the 00372 // rule that no exceptions can be thrown during destruction 00373 try 00374 { 00375 started_comps.back()->stop(); 00376 } 00377 catch (...) 00378 { 00379 ASSERT(!"exception caught in stop()!"); 00380 } 00381 started_comps.pop_back(); 00382 } 00383 00384 // now re-throw the exception 00385 throw; 00386 } 00387 } 00388 00389 // ###################################################################### 00390 bool ModelComponent::started() const 00391 { return rep->started; } 00392 00393 // ###################################################################### 00394 void ModelComponent::stop() 00395 { 00396 if (rep->started == false) 00397 CLFATAL("ModelComponent '%s' not started", rep->dname.c_str()); 00398 00399 GVX_ERR_CONTEXT(rutz::sfmt("stopping %s '%s'", 00400 this->obj_typename().c_str(), 00401 this->tagName().c_str())); 00402 00403 CLDEBUG(">>>> Stopping..."); 00404 00405 // do our shutdown that is before our subs have been stopped: 00406 this->stop1(); 00407 00408 // stop our subcomponents in reverse order of addition: 00409 SubCompVec::iterator citr = rep->subComps.end(); 00410 while(citr != rep->subComps.begin()) { -- citr; (*citr)->stop(); } 00411 00412 // do our shutdown that is after our subs have been stopped: 00413 this->stop2(); 00414 00415 // we are stopped: 00416 rep->started = false; 00417 CLDEBUG("<<<< Stopped"); 00418 } 00419 00420 // ###################################################################### 00421 void ModelComponent::managerDestroyed() 00422 { 00423 //CLINFO("managerDestroyed"); 00424 00425 rep->mgr = NULL; 00426 00427 // also let all our subcomponents know about this sad situation: 00428 SubCompVec::iterator citr = rep->subComps.begin(); 00429 while(citr != rep->subComps.end()) 00430 { (*citr)->managerDestroyed(); citr ++; } 00431 } 00432 00433 // ###################################################################### 00434 void ModelComponent::printout(std::ostream& s, const std::string& prefix) const 00435 { 00436 // add our tag name to the prefix: 00437 std::string newprefix; 00438 if (prefix.size()) 00439 { 00440 if (isspace(prefix[prefix.size()-1])) 00441 newprefix = prefix + rep->realm + ":" + rep->tname; 00442 else 00443 newprefix = prefix + "." + rep->realm + ":" + rep->tname; 00444 } 00445 else 00446 newprefix = rep->realm + ":" + rep->tname; 00447 00448 // first, call printout() on all our ModelParam's, in the order in which 00449 // they registered with us: 00450 for (size_t i = 0; i < rep->pinfos.size(); ++i) 00451 rep->pinfos[i].param->printout(s, newprefix); 00452 00453 // then call printout() on all our subcomponents, in the order in 00454 // which thery were added: 00455 SubCompVec::const_iterator citr = rep->subComps.begin(); 00456 while(citr != rep->subComps.end()) 00457 { (*citr)->printout(s, newprefix); citr ++; } 00458 } 00459 00460 // ###################################################################### 00461 void ModelComponent::start1() 00462 { } 00463 00464 // ###################################################################### 00465 void ModelComponent::start2() 00466 { } 00467 00468 // ###################################################################### 00469 void ModelComponent::stop1() 00470 { } 00471 00472 // ###################################################################### 00473 void ModelComponent::stop2() 00474 { } 00475 00476 // ###################################################################### 00477 void ModelComponent::reset1() 00478 { } 00479 00480 // ###################################################################### 00481 void ModelComponent::reset2() 00482 { } 00483 00484 // ###################################################################### 00485 void ModelComponent::save1(const ModelComponentSaveInfo& sinfo) 00486 { } 00487 00488 // ###################################################################### 00489 void ModelComponent::save2(const ModelComponentSaveInfo& sinfo) 00490 { } 00491 00492 // ###################################################################### 00493 std::string ModelComponent::descriptiveName() const 00494 { return rep->dname; } 00495 00496 // ###################################################################### 00497 void ModelComponent::setDescriptiveName(const std::string& name) 00498 { rep->dname = name; } 00499 00500 // ###################################################################### 00501 std::string ModelComponent::tagName() const 00502 { return rep->tname; } 00503 00504 // ###################################################################### 00505 void ModelComponent::setTagName(const std::string& name) 00506 { rep->tname = name; } 00507 00508 // ###################################################################### 00509 std::string ModelComponent::realm() const 00510 { return rep->realm; } 00511 00512 // ###################################################################### 00513 void ModelComponent::setRealm(const std::string& crealm) 00514 { 00515 if (started()) CLFATAL("Too late to set realm after start()..."); 00516 rep->realm = crealm; 00517 00518 // recurse through all subcomponents: 00519 SubCompVec::const_iterator itr = rep->subComps.begin(); 00520 while(itr != rep->subComps.end()) (*itr++)->setRealm(crealm); 00521 } 00522 00523 // ###################################################################### 00524 ModelComponent* ModelComponent::getParent() const 00525 { 00526 // will return null if the smart pointer has no pointee 00527 return rep->parent.get_weak(); 00528 } 00529 00530 // ###################################################################### 00531 ModelComponent* ModelComponent::getRootObject() 00532 { 00533 ModelComponent* p = this; 00534 while (p->getParent() != 0) 00535 p = p->getParent(); 00536 return p; 00537 } 00538 00539 // ###################################################################### 00540 const ModelComponent* ModelComponent::getRootObject() const 00541 { 00542 const ModelComponent* p = this; 00543 while (p->getParent() != 0) 00544 p = p->getParent(); 00545 return p; 00546 } 00547 00548 // ###################################################################### 00549 uint ModelComponent::addSubComponent(const nub::ref<ModelComponent>& subc, const bool propagate_realm) 00550 { 00551 if (subc->getParent() != 0) 00552 LERROR("ModelComponent %s is already a subcomponent of %s, creating loop in component tree", 00553 subc->tagName().c_str(), subc->getParent()->tagName().c_str()); 00554 else 00555 // make the parent a WEAK pointer to this; that we we avoid 00556 // cyclic references: parent holds a strong pointer to child, 00557 // child holds a weak pointer to parent 00558 subc->rep->parent = nub::soft_ref<ModelComponent>(this, nub::WEAK); 00559 00560 // recursively set the realm of the sub 00561 if (propagate_realm) subc->setRealm(rep->realm); 00562 00563 // add it to our list of subs: 00564 rep->subComps.push_back(subc); 00565 return rep->subComps.size() - 1; 00566 } 00567 00568 // ###################################################################### 00569 int ModelComponent::removeSubComponent(const ModelComponent& subc, 00570 bool removeall) 00571 { 00572 SubCompVec::iterator citr = rep->subComps.begin(); 00573 int numremoved = 0; 00574 while (citr != rep->subComps.end()) 00575 { 00576 if ((*citr).get() == &subc) 00577 { 00578 citr = rep->subComps.erase(citr); 00579 ++numremoved; 00580 00581 if (!removeall) 00582 break; 00583 } 00584 else 00585 citr ++; 00586 } 00587 00588 if (0 == numremoved) 00589 CLERROR("Request to erase unknown subcomponent -- IGNORED"); 00590 00591 return numremoved; 00592 } 00593 00594 // ###################################################################### 00595 void ModelComponent::removeSubComponent(const uint idx) 00596 { 00597 if (idx >= rep->subComps.size()) 00598 CLERROR("Attempt to remove subcomp whith index beyond range -- IGNORED"); 00599 else { 00600 SubCompVec::iterator citr = rep->subComps.begin(); 00601 citr += idx; rep->subComps.erase(citr); 00602 } 00603 } 00604 00605 // ###################################################################### 00606 void ModelComponent::removeSubComponent(const std::string& tagname) 00607 { 00608 SubCompVec::iterator citr = rep->subComps.begin(); 00609 while(citr != rep->subComps.end()) { 00610 if (tagname.compare((*citr)->tagName()) == 0) 00611 { rep->subComps.erase(citr); return; } 00612 citr ++; 00613 } 00614 CLFATAL("Cannot find subComponent '%s'", tagname.c_str()); 00615 } 00616 00617 // ###################################################################### 00618 void ModelComponent::removeSubComponent(const nub::ref<ModelComponent>& subc) 00619 { 00620 removeSubComponent(subc->tagName().c_str()); 00621 } 00622 00623 // ###################################################################### 00624 void ModelComponent::removeAllSubComponents() 00625 { while(rep->subComps.size()) rep->subComps.pop_back(); } 00626 00627 // ###################################################################### 00628 nub::ref<ModelComponent> ModelComponent::subComponent(const uint idx) const 00629 { 00630 if (idx >= rep->subComps.size()) 00631 CLFATAL("%s: request for subcomponent %u but I have only %"ZU" -- FATAL", 00632 rep->dname.c_str(), idx, rep->subComps.size()); 00633 return rep->subComps[idx]; 00634 } 00635 00636 // ###################################################################### 00637 nub::ref<ModelComponent> 00638 ModelComponent::subComponent(const std::string& tagname, 00639 const ModelFlag flags) const 00640 { 00641 SubCompVec::const_iterator 00642 itr = rep->subComps.begin(); 00643 while(itr != rep->subComps.end()) { 00644 // is the one we are looking for one of our subcomponents? 00645 if (tagname.compare((*itr)->tagName()) == 0) return *itr; 00646 00647 // otherwise, if recursive, see whether it's a subcomp of the current: 00648 if ((flags & MC_RECURSE) && (*itr)->hasSubComponent(tagname, flags)) 00649 return (*itr)->subComponent(tagname, flags); 00650 00651 itr ++; 00652 } 00653 CLFATAL("Cannot find subComponent '%s'", tagname.c_str()); 00654 return nub::ref<ModelComponent>((ModelComponent*)0); // keep g++ happy 00655 } 00656 00657 // ###################################################################### 00658 uint ModelComponent::numSubComp() const 00659 { return rep->subComps.size(); } 00660 00661 // ###################################################################### 00662 bool ModelComponent::hasSubComponent(const std::string& tagname, 00663 const ModelFlag flags) const 00664 { 00665 SubCompVec::const_iterator 00666 itr = rep->subComps.begin(); 00667 while(itr != rep->subComps.end()) { 00668 // is the one we are looking for one of our subcomponents? 00669 if (tagname.compare((*itr)->tagName()) == 0) return true; 00670 00671 // otherwise, if recursive, see whether it's a subcomp of the current: 00672 if ((flags & MC_RECURSE) && (*itr)->hasSubComponent(tagname, flags)) 00673 return true; 00674 itr ++; 00675 } 00676 // nowhere to be found 00677 return false; 00678 } 00679 00680 // ###################################################################### 00681 bool ModelComponent::hasSubComponent(const nub::soft_ref<ModelComponent>& c, 00682 const ModelFlag flags) const 00683 { 00684 SubCompVec::const_iterator 00685 itr = rep->subComps.begin(); 00686 while(itr != rep->subComps.end()) { 00687 // is the one we are looking for one of our subcomponents? 00688 if (c.getWeak() == itr->get()) return true; 00689 00690 // otherwise, if recursive, see whether it's a subcomp of the current: 00691 if ((flags & MC_RECURSE) && (*itr)->hasSubComponent(c, flags)) 00692 return true; 00693 itr ++; 00694 } 00695 // nowhere to be found 00696 return false; 00697 } 00698 00699 // ###################################################################### 00700 void ModelComponent::exportOptions(const ModelFlag flags) 00701 { 00702 // in the base class implementation, we do nothing for us proper... 00703 CLDEBUG(">>>> Exporting Options..."); 00704 00705 /* if recursive, let's propagate to the subcomps 00706 00707 NOTE! We must do this BEFORE exporting our own options! 00708 00709 Why? Suppose we exported our own options before exporting subcomp 00710 options, and consider this situation: we have one option X, and 00711 we have one subcomponent A that has its own option Y. Suppose 00712 that in our paramChanged() function, when we detect that X has 00713 been changed, we propagate some related change to A's Y 00714 option. Now if our options our exported first, then when X is 00715 first exported that will trigger a paramChanged() cause us to set 00716 A's Y, but when we then propagate exportOptions() to 00717 subcomponents, A's Y option will be overwritten with its default 00718 option value, and our desired value based on X will have been 00719 lost. Therefore we need to export subcomp options before our 00720 own. This fits with the general rule that subcomps should be 00721 fully constructed/useable before the owning object tries to use 00722 them (just like c++ subobjects and base classes must be fully 00723 constructed before the containing object uses them). 00724 */ 00725 if (flags & MC_RECURSE) 00726 { 00727 SubCompVec::iterator citr=rep->subComps.begin(); 00728 while(citr != rep->subComps.end()) { 00729 (*citr)->exportOptions(flags); 00730 citr ++; 00731 } 00732 } 00733 00734 // loop over our param list, looking for params that have 00735 // command-line options (i.e., are of class OptionedModelParam 00736 // rather than plain ModelParamBase): 00737 00738 for (size_t i = 0; i < rep->pinfos.size(); ++i) 00739 { 00740 if (rep->pinfos[i].oparam != 0 && rep->pinfos[i].exportMe == true) 00741 rep->mgr->requestOption(*(rep->pinfos[i].oparam), rep->pinfos[i].useMyVal); 00742 } 00743 00744 CLDEBUG("<<<< Exported Options"); 00745 00746 rep->hasBeenExported = true; 00747 } 00748 00749 // ###################################################################### 00750 bool ModelComponent::hasModelParam(const std::string& name, 00751 const ModelFlag flags) const 00752 { 00753 std::vector<ParamInfo> matches; 00754 rep->findMatchingParams(name, flags, matches); 00755 return (matches.size() > 0); 00756 } 00757 00758 // ###################################################################### 00759 void ModelComponent::setModelParamString(const std::string& name, 00760 const std::string& value, 00761 const ModelFlag flags) 00762 { 00763 std::vector<ParamInfo> matches; 00764 rep->findMatchingParams(name, flags, matches); 00765 00766 for (uint i = 0; i < matches.size(); ++i) 00767 { 00768 GVX_ERR_CONTEXT 00769 (rutz::sfmt 00770 ("setting parameter '%s' in component '%s'", 00771 name.c_str(), matches[i].client->descriptiveName().c_str())); 00772 00773 if (rep->started && !matches[i].param->allowsOnlineChanges()) 00774 LFATAL("Cannot change parameter '%s' values while started", 00775 matches[i].param->getName().c_str()); 00776 00777 matches[i].param->setValString(value); 00778 } 00779 } 00780 00781 // ###################################################################### 00782 std::string ModelComponent::getModelParamString(const std::string& name, 00783 const ModelFlag flags) const 00784 { 00785 if (flags & MC_IGNORE_MISSING) 00786 CLFATAL("MC_IGNORE_MISSING not allowed for getting param values"); 00787 00788 std::vector<ParamInfo> matches; 00789 rep->findMatchingParams(name, flags, matches); 00790 00791 // we don't allow MC_IGNORE_MISSING, so we should always get a 00792 // non-empty set back from findMatchingParams(): 00793 ASSERT(matches.size() > 0); 00794 00795 GVX_ERR_CONTEXT 00796 (rutz::sfmt 00797 ("getting parameter '%s' from component '%s'", 00798 name.c_str(), matches[0].client->descriptiveName().c_str())); 00799 00800 // by convention, we use the value from the first matching param 00801 // (even though there may have been more than one) 00802 return matches[0].param->getValString(); 00803 } 00804 00805 // ###################################################################### 00806 bool ModelComponent::doRequestOption(const ModelOptionDef* opt, 00807 const bool useMyVal, 00808 const bool recurse, 00809 const bool warn) 00810 { 00811 if (rep->started) 00812 CLFATAL("Cannot request an option while started"); 00813 bool gotit = false; 00814 00815 // look a ParamInfo that has an OptionedModelParam with a matching 00816 // ModelOptionDef 00817 for (size_t i = 0; i < rep->pinfos.size(); ++i) 00818 { 00819 if (rep->pinfos[i].oparam != 0 && rep->pinfos[i].oparam->getOptionDef() == opt) 00820 { 00821 rep->pinfos[i].exportMe = true; 00822 rep->pinfos[i].useMyVal = useMyVal; 00823 00824 rep->mgr->requestOption(*(rep->pinfos[i].oparam), useMyVal); 00825 gotit = true; 00826 } 00827 } 00828 00829 // if recurse is true, let's also see if our subcomps have it: 00830 if (recurse) 00831 { 00832 SubCompVec::iterator citr=rep->subComps.begin(); 00833 while(citr != rep->subComps.end()) { 00834 gotit |= (*citr)->doRequestOption(opt, useMyVal, recurse, false); 00835 citr ++; 00836 } 00837 } 00838 00839 if (warn && gotit == false) 00840 CLERROR("No ModelParam named '%s' -- IGNORED", opt->name); 00841 return gotit; 00842 } 00843 00844 // ###################################################################### 00845 void ModelComponent::hideOption(const ModelOptionDef* opt) 00846 { 00847 if (rep->started) CLFATAL("Cannot hide an option while started"); 00848 if (rep->hasBeenExported) CLFATAL("Cannot hide an option that has already been exported"); 00849 00850 // lookup a ParamInfo that has an OptionedModelParam with a matching ModelOptionDef: 00851 for (size_t i = 0; i < rep->pinfos.size(); ++i) 00852 if (rep->pinfos[i].oparam != 0 && rep->pinfos[i].oparam->getOptionDef() == opt) 00853 { 00854 rep->pinfos[i].exportMe = false; 00855 return; 00856 } 00857 00858 CLFATAL("No ModelParam named '%s'", opt->name); 00859 } 00860 00861 // ###################################################################### 00862 size_t ModelComponent::getNumModelParams() const 00863 { 00864 return rep->pinfos.size(); 00865 } 00866 00867 // ###################################################################### 00868 const ModelParamBase* ModelComponent::getModelParam(size_t i) const 00869 { 00870 if (i >= rep->pinfos.size()) 00871 LFATAL("Oops! Request to access model param %"ZU", but I have only " 00872 "%"ZU" params", i, rep->pinfos.size()); 00873 00874 return rep->pinfos[i].param; 00875 } 00876 00877 // ###################################################################### 00878 ModelParamBase* ModelComponent::getModelParam(size_t i) 00879 { 00880 if (i >= rep->pinfos.size()) 00881 LFATAL("Oops! Request to access model param %"ZU", but I have only " 00882 "%"ZU" params", i, rep->pinfos.size()); 00883 00884 return rep->pinfos[i].param; 00885 } 00886 00887 // ###################################################################### 00888 void ModelComponent::readParamsFrom(const ParamMap& pmap, const bool noerr) 00889 { 00890 if (rep->started) 00891 CLFATAL("Cannot read ModelParam values while started"); 00892 00893 // if we want to ignore missing pinfos, check first whether we have one: 00894 if (noerr && pmap.hasParam(rep->tname) == false) return; 00895 00896 // we should have a submap for all our stuff (will trigger error otherwise): 00897 rutz::shared_ptr<ParamMap> submap = pmap.getSubpmap(rep->tname); 00898 00899 // ok, do our own pinfos: 00900 for (size_t i = 0; i < rep->pinfos.size(); ++i) 00901 rep->pinfos[i].param->readFrom(*submap, noerr); 00902 00903 // then go over our subcomponents, and recurse: 00904 SubCompVec::iterator citr = rep->subComps.begin(); 00905 while(citr != rep->subComps.end()) 00906 { (*citr)->readParamsFrom(*submap, noerr); citr ++; } 00907 } 00908 00909 // ###################################################################### 00910 void ModelComponent::writeParamsTo(ParamMap& pmap) const 00911 { 00912 // if (rep->started) 00913 // CLERROR("It is not safe to write ModelParam values while started"); 00914 00915 // first, create a submap for all our stuff: 00916 rutz::shared_ptr<ParamMap> submap(new ParamMap); 00917 00918 // then, do our own pinfos: 00919 for (size_t i = 0; i < rep->pinfos.size(); ++i) 00920 rep->pinfos[i].param->writeTo(*submap); 00921 00922 // then go over our subcomponents, and recurse: 00923 SubCompVec::const_iterator citr = rep->subComps.begin(); 00924 while(citr != rep->subComps.end()) 00925 { (*citr)->writeParamsTo(*submap); citr ++; } 00926 00927 // finally add this new submap to our incoming pmap: 00928 pmap.putSubpmap(rep->tname, submap); 00929 } 00930 00931 // ###################################################################### 00932 void ModelComponent::registerParam(ModelParamBase* mp) 00933 { 00934 rep->addParam(ParamInfo(this, mp)); 00935 } 00936 00937 // ###################################################################### 00938 void ModelComponent::registerOptionedParam(OptionedModelParam* mp, 00939 const ParamFlag flags) 00940 { 00941 // don't do rep->mgr->requestOption() right away, instead we'll wait 00942 // and do that inside ModelComponent::exportOptions() where we loop 00943 // over rep->pinfos 00944 if (flags & USE_MY_VAL) 00945 rep->addParam(ParamInfo(this, mp, true)); 00946 else 00947 rep->addParam(ParamInfo(this, mp, false)); 00948 } 00949 00950 // ###################################################################### 00951 void ModelComponent::unregisterParam(const ModelParamBase* mp) 00952 { 00953 bool gotit = false; 00954 00955 for (size_t i = 0; i < rep->pinfos.size(); /* increment in loop body */) 00956 { 00957 if (rep->pinfos[i].param == mp) 00958 { 00959 if (rep->mgr != 0 && rep->pinfos[i].oparam != 0) 00960 rep->mgr->unRequestOption(*rep->pinfos[i].oparam); 00961 rep->pinfos.erase(rep->pinfos.begin() + i); 00962 gotit = true; 00963 } 00964 else 00965 ++i; 00966 } 00967 00968 if (gotit == false) 00969 CLERROR("Request to unregister unknown parameter"); 00970 } 00971 00972 // ###################################################################### 00973 void ModelComponent::paramChanged(ModelParamBase* const param, 00974 const bool valueChanged, 00975 ParamClient::ChangeStatus* status) 00976 {} 00977 00978 // ###################################################################### 00979 void ModelComponent::forgetExports() 00980 { 00981 for (size_t i = 0; i < rep->pinfos.size(); ++i) 00982 rep->pinfos[i].exportMe = false; 00983 } 00984 00985 // ###################################################################### 00986 void ModelComponent::reset(const ModelFlag flags) 00987 { 00988 if (rep->started == false) 00989 CLFATAL("ModelComponent '%s' must be started before reset()", 00990 rep->dname.c_str()); 00991 00992 this->reset1(); 00993 00994 // if recursive, let's propagate to the subcomps: 00995 if (flags & MC_RECURSE) 00996 { 00997 for (SubCompVec::iterator 00998 citr = rep->subComps.begin(), 00999 stop = rep->subComps.end(); 01000 citr != stop; ++citr) 01001 (*citr)->reset(flags); 01002 } 01003 01004 this->reset2(); 01005 } 01006 01007 // ###################################################################### 01008 void ModelComponent::save(const ModelComponentSaveInfo& sinfo, 01009 const ModelFlag flags) 01010 { 01011 if (rep->started == false) 01012 CLFATAL("ModelComponent '%s' must be started before save()", 01013 rep->dname.c_str()); 01014 01015 this->save1(sinfo); 01016 01017 // if recursive, let's propagate to the subcomps: 01018 if (flags & MC_RECURSE) 01019 { 01020 for (SubCompVec::iterator 01021 citr = rep->subComps.begin(), 01022 stop = rep->subComps.end(); 01023 citr != stop; ++citr) 01024 (*citr)->save(sinfo, flags); 01025 } 01026 01027 this->save2(sinfo); 01028 } 01029 01030 // ###################################################################### 01031 OptionManager& ModelComponent::getManager() const 01032 { 01033 return *rep->mgr; 01034 } 01035 01036 // ###################################################################### 01037 void ModelComponent::setManager(OptionManager& mgr) 01038 { 01039 ASSERT(rep->mgr == 0); 01040 rep->mgr = &mgr; 01041 } 01042 01043 // ###################################################################### 01044 bool ModelComponent::hasBeenExported() const 01045 { 01046 return rep->hasBeenExported; 01047 } 01048 01049 // ###################################################################### 01050 void ModelComponent::setModelParamValAux(const std::string& name, 01051 const RefHolder& ref, 01052 const ModelFlag flags) 01053 { 01054 std::vector<ParamInfo> matches; 01055 rep->findMatchingParams(name, flags, matches); 01056 01057 // change the param val for all matching model params (this will 01058 // include params from our subcomponents if 'recurse' is true) 01059 for (uint i = 0; i < matches.size(); ++i) 01060 { 01061 GVX_ERR_CONTEXT 01062 (rutz::sfmt 01063 ("setting parameter '%s' in component '%s'", 01064 name.c_str(), matches[i].client->descriptiveName().c_str())); 01065 01066 if (rep->started && !matches[i].param->allowsOnlineChanges()) 01067 LFATAL("Cannot change parameter '%s' values while started", 01068 matches[i].param->getName().c_str()); 01069 01070 matches[i].param->setValGeneric(ref); 01071 } 01072 } 01073 01074 // ###################################################################### 01075 void ModelComponent::getModelParamValAux(const std::string& name, 01076 RefHolder& ref, 01077 const ModelFlag flags) const 01078 { 01079 if (flags & MC_IGNORE_MISSING) 01080 CLFATAL("MC_IGNORE_MISSING not allowed for getting param values"); 01081 01082 std::vector<ParamInfo> matches; 01083 rep->findMatchingParams(name, flags, matches); 01084 01085 // we don't allow MC_IGNORE_MISSING, so we should always get a 01086 // non-empty set back from findMatchingParams(): 01087 ASSERT(matches.size() > 0); 01088 01089 GVX_ERR_CONTEXT 01090 (rutz::sfmt 01091 ("getting parameter '%s' from component '%s'", 01092 name.c_str(), matches[0].client->descriptiveName().c_str())); 01093 01094 // by convention, we use the value from the first matching param 01095 // (even though there may have been more than one) 01096 matches[0].param->getValGeneric(ref); 01097 } 01098 01099 // ###################################################################### 01100 /* So things look consistent in everyone's emacs... */ 01101 /* Local Variables: */ 01102 /* indent-tabs-mode: nil */ 01103 /* End: */