ModelComponent.C

Go to the documentation of this file.
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: */
Generated on Sun May 8 08:04:42 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3