Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

parametermap.h

Go to the documentation of this file.
00001 
00007 #ifndef ___PARAMETERMAP_H___
00008 #define ___PARAMETERMAP_H___
00009 
00010 #include <math.h>
00011 #include <map>
00012 #include <algorithm>
00013 #include <vector>
00014 
00015 #include "parameter.h"
00016 #include "stringutils.h"
00017 #include "stringparser.h"
00018 #include "pathspecification.h"
00019 #include "pointerlookup.h"
00020 #include "parammap.h"
00021 #include "msg.h"
00022 #include "generic_stdlib.h"
00023 #include "mathconstants.h"
00024 
00025 
00026 
00039 template<class ParamT=ParameterDefinition<> > 
00040 class ParameterMap : public ParamMap {
00041 public:
00042   typedef ParamT               ParamType;
00043   typedef ParameterMap<ParamT> self;
00044   typedef ParamType            value_type;
00045 
00046   virtual ~ParameterMap() {
00047     /* Before dying, sever all links to us */
00048     if (parent) parent->children.erase(name()); /* Make our parent forget us */
00049     for (typename ChildListType::const_iterator c=children.begin(); c!=children.end(); c++)
00050       (*c).second->parent=0; /* Make our children consider themselves parentless */
00051     Generic::delete_contents(allocated);
00052   }
00053 
00054   
00060   ParameterMap(self* parent_i=0, const string name_="")
00061     : parent(parent_i), name_str(name_)
00062     {  if (parent) parent->children[name()]=this;  }
00063 
00064   virtual self* new_child(const string name_="", const bool owned=false) {
00065     self* p=new self(this,name_);
00066     if (owned) allocated.push_back(p);
00067     return p;
00068   }
00069 
00070   void    init_hook(void);
00071   int     define_param(const ParamType& param);
00072   void    add_constants();
00073   void    update_all_default_values(const StringParser& sp);
00074 
00075   virtual const ParamType& lookup(const string& name, bool warn=true) const;
00076   virtual       ParamType& lookup(const string& name, bool warn=true);
00077   virtual       ParamType& local_copy(ParamType& param, bool notify=true, bool copysetfn=true);
00078 
00079 
00080   /* Macro: silently ensure that the given parameters exists in the
00081      local map and set it to the given value. */
00082   template <class T>
00083   self& set_local(const string& name, const T& value)
00084     {  local_copy(lookup(name),false).datavalue().set(Polymorph<T>(value));  return *this;  }
00085 
00086   virtual ParamMap& get_child(const string& name_="")
00087     {  return lookup_map(name_);  }
00088 
00090   virtual const ParamMap& get_child(const string& name_="") const
00091     {  return const_cast<self*>(this)->lookup_map(name_);  }
00092 
00094   const self& root() const 
00095     {  return (parent? parent->root() : *this);  }
00096   self& root() {  return (parent? parent->root() : *this);  }
00097     
00098   
00112   self& lookup_map(const string& mapname, bool warn=true) {
00113     const PathSpecification path(mapname);
00114     return lookup_map(path.all(),warn,path.isrooted());
00115   }
00116 
00122   self& lookup_map(const PathSpecification::NameList& names, bool warn, bool isrooted) {
00123     self& startmap=(isrooted? root() : *this);
00124     if (names.empty()) return startmap;
00125     PathSpecification::NameList::const_iterator rest=names.begin();
00126     self& child=startmap.lookup_child(*rest++, warn);
00127     PathSpecification::NameList remainder(rest,names.end());
00128     return child.lookup_map(remainder,warn,false);
00129   }
00130   const self& lookup_map(const PathSpecification::NameList& names, bool warn, bool isrooted) const {
00131     const self& startmap=(isrooted? root() : *this);
00132     if (names.empty()) return startmap;
00133     PathSpecification::NameList::const_iterator rest=names.begin();
00134     const self& child=startmap.lookup_child(*rest++, warn);
00135     PathSpecification::NameList remainder(rest,names.end());
00136     return child.lookup_map(remainder,warn,false);
00137   }
00138   
00139   /* Macro: set parameter to the given valuestr (creating a copy of
00140      the param locally if necessary) in all matching paths (accepting
00141      * to represent all children at a given level).  Returns the
00142      number of parameters actually set. */
00143   int set_matching(const StringParser& sp, const string& pathspec, const string& valuestr,
00144                    const bool mark=true, const bool verbose=true,
00145                    const bool local_only=false, const bool copysetfn=true ) {
00146     PathSpecification path(pathspec);
00147     PathSpecification::NameList namelist=path.allbutlast();
00148     return (path.isrooted()? root() : *this).
00149       set_matching(sp,namelist.begin(),namelist.end(),path.last(),valuestr,mark,verbose,local_only, copysetfn);
00150   }
00151   
00152 
00154   inline ParamType& lookup_with_path(const string& pathspec, bool warn=true) {
00155     PathSpecification path(pathspec);
00156     return lookup_map(path.allbutlast(),true,path.isrooted()).lookup(path.last(),warn);
00157   }
00158   inline const ParamType& lookup_with_path(const string& pathspec, bool warn=true) const {
00159     PathSpecification path(pathspec);    
00160     return lookup_map(path.allbutlast(),true,path.isrooted()).lookup(path.last(),warn);
00161   }
00162 
00164   Typeless* getptr(const key_type& k) {
00165     ParamType& existing = lookup_with_path(k,true);
00166     return (existing.is_valid() ? &(existing.datavalue()) : 0);
00167   }
00168 
00170   const Typeless* getptr(const key_type& k) const {
00171     const ParamType& existing = lookup_with_path(k,true);
00172     return (existing.is_valid() ? &(existing.datavalue()) : 0);
00173   }
00174 
00175   
00176   int     check_all( void ) const;
00177 
00178   void    print_all(            FILE *fp, const string& prefix="") const;
00179   void    print_constants(      FILE *fp, const string& prefix="") const;
00180   void    print_constants_doc(  FILE *fp, const string& prefix="") const;
00181   void    print_children(       FILE *fp, const string& prefix="") const;
00182   void    print_parameters(     FILE *fp, const string& prefix="") const;
00183   void    print_parameters_doc( FILE *fp, const string& prefix="") const;
00184   void    save_parameters(      FILE *fp, const string& prefix="") const;
00185   
00186   char*   completion_generator (char *text, int state) const;
00187   
00188   static const char* const help_separator;
00189 
00190   void message(Msg::MessageLevel m, const string& s) const {  ParamType::message(m,s);  }
00191 
00193   const string& name()       const {  return name_str;  }
00194 
00196   const string  path_name()  const {
00197     return (parent && (parent->path_name()!="") ?
00198             (parent->path_name()+"::")+name() :
00199             name());
00200   }
00201   
00204   const string  path_prefix()  const {
00205     const string path = path_name();
00206     return path + (path == "" ? "" : "::");
00207   }
00208 
00209   /* Merges the local values from another parameter set into this one */
00210   void merge(const self& b, const bool overwrite=true) {
00211     for (typename DataType::const_iterator i=b.data.begin(); i!=b.data.end(); i++) {
00212       if (overwrite || !local_lookup(i->name(),false).is_valid())
00213         local_copy(lookup(i->name()),false).datavalue().set(i->datavalue());
00214     }
00215   }
00216 
00217   /* Returns true if a parameter by the given name is defined in this map */
00218   bool defined_locally(const string& name) const 
00219     {  return local_lookup(name,false).is_valid();  }
00220   
00221   
00222 private:
00223   self& lookup_child(const string& childname, bool warn=true) {
00224     typename ChildListType::iterator location = children.find(childname);
00225     if (location==children.end()) {
00226       if (warn)
00227         message(Msg::Error,"Could not locate parameter set '"+childname+"'; using default set");
00228       return *this;
00229     }
00230     return *((*location).second);
00231   }
00232   const self& lookup_child(const string& childname, bool warn=true) const {
00233     typename ChildListType::const_iterator location = children.find(childname);
00234     if (location==children.end()) {
00235       if (warn)
00236         message(Msg::Error,"Could not locate parameter set '"+childname+"'; using default set");
00237       return *this;
00238     }
00239     return *((*location).second);
00240   }
00241 
00242   
00243   /* Recursive implementation of public set_matching routine. */
00244   int set_matching(const StringParser& sp,
00245                    const PathSpecification::NameList::const_iterator& pathbegin,
00246                    const PathSpecification::NameList::const_iterator& pathend,
00247                    const string& paramname,
00248                    const string& valuestr,
00249                    const bool mark, const bool verbose,
00250                    const bool local_only, const bool copysetfn) {
00251     /* If no path and the parameter definition exists, set in this blackboard */
00252     if (pathbegin==pathend) {
00253       ParamType& param = lookup(paramname);
00254       if (param.is_valid()) {
00255         ParamType& existinglocal = local_lookup(paramname,false);
00256         if (!local_only || existinglocal.is_valid())
00257           return local_copy(param,verbose,copysetfn).set(sp,valuestr,mark,verbose,path_prefix());
00258       }
00259       return 0;
00260     }
00261 
00262     PathSpecification::NameList::const_iterator rest=pathbegin;
00263     const string mapname=*rest++;
00264 
00265     /* Set in all matching children. */
00266     int numset=0;
00267     int nummaps=0;
00268     for (typename ChildListType::iterator c=children.begin(); c!=children.end(); c++) {
00269       const string childname=(*c).first;
00270       /* Supporting real globbing or a regex here might be nice */
00271       if (String::glob_match(mapname,childname)) {
00272         nummaps++;
00273         numset+= ((*c).second)->set_matching(sp,rest,pathend,paramname,valuestr,
00274                                              mark,verbose,local_only,copysetfn);
00275       }
00276     }
00277     if (!nummaps) message(Msg::Error,"No parameter set matches `" + path_prefix() + mapname + "'");
00278     return numset;
00279   }
00280   
00281 
00282         ParamType& local_lookup(const string& name, bool warn);
00283   const ParamType& local_lookup(const string& name, bool warn) const;
00284   
00285   typedef std::vector<ParamType>       DataType;
00286   typedef std::map<const string,self*> ChildListType;
00287 
00288   DataType data;
00289   ChildListType children;
00290   
00291   std::vector<ParamMap*> allocated;
00292   
00293   self* parent;
00294   const string name_str;
00295 };
00296 
00297 template<class ParamT>
00298 const char* const ParameterMap<ParamT>::help_separator=
00299 "_______________________________________________________________________________\n";
00300 
00301 
00302 
00303 
00305 #define DEFCONST(type,name,location,doc) ParamType \
00306 param_ ## name = ParamType(make_Polymorph(&location),#name,true);\
00307 param_ ## name.add_doc(doc); \
00308 define_param(param_ ## name)
00309 
00310 template<class ParamT>
00311 void ParameterMap<ParamT>::add_constants()
00312 {
00313   static double   mpi = (Math::pi);
00314   static Tristate tru = True;
00315   static Tristate fal = False;
00316   static Tristate uni = Uninitialized;
00317   static int      mxi = INT_MAX-1;
00318   static int      mni = INT_MIN+1;
00319   
00320   DEFCONST(DOUBLE,PI,            mpi,"Symbol representing PI.");
00321   DEFCONST(3BOOL, true,          tru,"Symbol representing Boolean `True'.");
00322   DEFCONST(3BOOL, false,         fal,"Symbol representing Boolean `False'.");
00323   DEFCONST(3BOOL, True,          tru,"Symbol representing Boolean `True'.");
00324   DEFCONST(3BOOL, False,         fal,"Symbol representing Boolean `False'.");
00325   DEFCONST(3BOOL, Yes,           tru,"Symbol representing Boolean `True'.");
00326   DEFCONST(3BOOL, No,            fal,"Symbol representing Boolean `False'.");
00327   DEFCONST(3BOOL, Uninitialized, uni,"Symbol representing an uninitialized or default value.");
00328   DEFCONST(INT,   MaxInt,        mxi,"Symbol representing the maximum integer value.");
00329   DEFCONST(INT,   MinInt,        mni,"Symbol representing the minimum integer value.");
00330 }
00331 #undef DEFCONST
00332 
00333 
00334 
00340 template<class ParamT>
00341 void ParameterMap<ParamT>::init_hook( void )
00342 {
00343   /* Sort for pretty and to make user-defined ones separate. */
00344   std::sort(data.begin(),data.end());
00345 }
00346 
00347 
00348 
00351 template<class ParamT>
00352 const typename ParameterMap<ParamT>::ParamType&
00353 ParameterMap<ParamT>::local_lookup(const string& name, bool warn) const
00354 {
00355   /* Counts backward, which is very quick if this parameter was just added */
00356   for (int idx=data.size()-1; idx>=0; idx--)
00357     if (name == data[idx].name())
00358       return data[idx];
00359   if (warn) message(Msg::Error,"No parameter (or constant) `" + name + "' is defined");
00360   static ParamType dummy;
00361   assert (!dummy.is_valid());
00362   return dummy;
00363 }
00364 
00365 
00366 
00368 template<class ParamT>
00369 typename ParameterMap<ParamT>::ParamType&
00370 ParameterMap<ParamT>::local_lookup(const string& name, bool warn)
00371 {
00372   /* Counts backward, which is very quick if this parameter was just added */
00373   for (int idx=data.size()-1; idx>=0; idx--)
00374     if (name == data[idx].name())
00375       return data[idx];
00376   if (warn) message(Msg::Error,"No parameter (or constant) `" + name + "' is defined");
00377   static ParamType dummy;
00378   return dummy;
00379 }
00380 
00381 
00382 
00395 template<class ParamT>
00396 typename ParameterMap<ParamT>::ParamType&
00397 ParameterMap<ParamT>::lookup(const string& name, bool warn)
00398 {
00399   ParamType& result = local_lookup(name,(warn && !parent));
00400   if (!result.is_valid() && parent) return parent->lookup(name,warn);
00401   return result;
00402 }
00403 
00404 
00405 
00406 /* Const version of lookup */
00407 template<class ParamT>
00408 const typename ParameterMap<ParamT>::ParamType&
00409 ParameterMap<ParamT>::lookup(const string& name, bool warn) const
00410 {
00411   const ParamType& result = local_lookup(name,(warn && !parent));
00412   if (!result.is_valid() && parent) return parent->lookup(name,warn);
00413   return result;
00414 }
00415 
00416 
00417 
00418 /*
00419   Copies the result from a non-const lookup() into the local map.
00420   This is generally done in preparation for a set() operation that is
00421   intended to affect the local map rather than the global one.
00422   Ignores invalid parameters and parameters already in the local map.
00423 */
00424 template<class ParamT>
00425 typename ParameterMap<ParamT>::ParamType&
00426 ParameterMap<ParamT>::local_copy(ParamType& param, bool notify, bool copysetfn)
00427 {
00428   if (param.is_valid()) {
00429     ParamType& result = local_lookup(param.name(),false);
00430     if (result.is_valid())
00431       return result;
00432     else {
00433       if (notify) message(Msg::Notify,"Adding " + param.name() + " to parameter set " + path_name());
00434       ParamType* copy = param.duplicate();
00435       if (!copysetfn) copy->add_setfn(0);
00436       data.push_back(*copy);
00437       delete copy;
00438       return data.back();
00439     }
00440   }
00441 
00442   return param;
00443 }
00444 
00445 
00446 
00450 template<class ParamT>
00451 int ParameterMap<ParamT>::check_all( void ) const
00452 {
00453   int numerrors=0;
00454 
00455   /* Check our data */
00456   for (typename DataType::const_iterator i=data.begin(); i!=data.end(); i++) {
00457     //message(Msg::Notify,"Checking " + (*i).name());    
00458     numerrors += (*i).check2();
00459   }
00460 
00461   /* Check children's data */
00462   for (typename ChildListType::const_iterator c=children.begin(); c!=children.end(); c++)
00463     numerrors += (*c).second->check_all();
00464 
00465   return numerrors;
00466 }
00467 
00468 
00469 
00471 template<class ParamT>
00472 void ParameterMap<ParamT>::print_all(FILE *fp, const string& prefix) const
00473 {
00474   /* Print our data */
00475   for (typename DataType::const_iterator i=data.begin(); i!=data.end(); i++)
00476     fprintf(fp,"%s\n",(*i).usage_string(prefix).c_str());
00477 
00478   /* Print children's data */
00479   for (typename ChildListType::const_iterator c=children.begin(); c!=children.end(); c++)
00480     (*c).second->print_all(fp,prefix+(*c).first+"::");
00481 }
00482 
00483 
00484 
00486 template<class ParamT>
00487 void ParameterMap<ParamT>::print_children(FILE *fp, const string& prefix) const
00488 {
00489   for (typename ChildListType::const_iterator c=children.begin(); c!=children.end(); c++) {
00490     const string new_prefix = prefix + (*c).first.c_str();
00491     fprintf(fp,"%s\n",new_prefix.c_str());
00492     (*c).second->print_children(fp,new_prefix + "::");
00493   }
00494 }
00495 
00496 
00497 
00499 template<class ParamT>
00500 void ParameterMap<ParamT>::print_parameters(FILE *fp, const string& prefix) const
00501 {
00502   /* Print our data */
00503   for (typename DataType::const_iterator i=data.begin(); i!=data.end(); i++)
00504     if (!(*i).is_constant())
00505       fprintf(fp,"%s\n",(*i).usage_string(prefix).c_str());
00506 
00507   /* Print children's data */
00508   for (typename ChildListType::const_iterator c=children.begin(); c!=children.end(); c++)
00509     (*c).second->print_parameters(fp,prefix+(*c).first+"::");
00510 }
00511 
00512 
00513 
00515 template<class ParamT>
00516 void ParameterMap<ParamT>::save_parameters(FILE *fp, const string& prefix) const
00517 {
00518   /* Print our data */
00519   for (typename DataType::const_iterator i=data.begin(); i!=data.end(); i++)
00520     if (!(*i).is_constant())
00521       fprintf(fp,"%s\n",(*i).print_to_str("::"+prefix).c_str());
00522 
00523   /* Print children's data */
00524   for (typename ChildListType::const_iterator c=children.begin(); c!=children.end(); c++)
00525     (*c).second->save_parameters(fp,prefix+(*c).first+"::");
00526 }
00527 
00528 
00530 template<class ParamT>
00531 void ParameterMap<ParamT>::print_constants(FILE *fp, const string& prefix) const
00532 {
00533   /* Print our data */
00534   for (typename DataType::const_iterator i=data.begin(); i!=data.end(); i++)
00535     if ((*i).is_constant())
00536       fprintf(fp,"%s\n",(*i).usage_string(prefix).c_str());
00537 
00538   /* Print children's data */
00539   for (typename ChildListType::const_iterator c=children.begin(); c!=children.end(); c++)
00540     (*c).second->print_constants(fp,prefix+(*c).first+"::");
00541 }
00542 
00543 
00544 
00549 template<class ParamT>
00550 int ParameterMap<ParamT>::define_param(const ParamType& param)
00551 {
00552   if (param.name().length() != String::C_identifier_length(param.name()))
00553     message(Msg::Warning,"Invalid characters in parameter name `" + param.name() + "'; can't define it");
00554   else {
00555     const ParamType& existing = lookup(param.name(),false);
00556     
00557     if (existing.is_valid()) {
00558       if (param.definition_matches(existing)) {
00559         //message(Msg::Notify,"Parameter " + param.name() + " already exists; not redefining it");
00560         return 2;
00561       }
00562       else message(Msg::Error,"Different parameter `" + param.name() + "' already exists; can't redefine it");
00563     }
00564     else if (!param.is_valid()) message(Msg::Error,"Could not construct parameter");
00565     else {
00566       data.push_back(param);
00567       return 1;
00568     }
00569   }
00570 
00571   return 0;
00572 }
00573 
00574 
00575 
00577 template<class ParamT>
00578 void ParameterMap<ParamT>::update_all_default_values(const StringParser& sp)
00579 {
00580   /* Update own values */
00581   for (typename DataType::iterator i=data.begin(); i!=data.end(); i++)
00582     (*i).update_default_value(sp);
00583 
00584   /* Update children */
00585   for (typename ChildListType::iterator c=children.begin(); c!=children.end(); c++)
00586     (*c).second->update_all_default_values(sp);
00587 }
00588 
00589 
00590 
00591 template<class ParamT>
00592 void ParameterMap<ParamT>::print_constants_doc(FILE *fp, const string& prefix) const
00593 {
00594   /* Only print separator at top level */
00595   if (prefix=="")
00596     fprintf(fp,"%s\n",help_separator);
00597   
00598   for (typename DataType::const_iterator i=data.begin(); i!=data.end(); i++)
00599     if ((*i).is_constant())
00600       fprintf(fp,"%s%s\n",(*i).doc_string(prefix).c_str(),help_separator);
00601 
00602 
00603   /* Print children's data */
00604   for (typename ChildListType::const_iterator c=children.begin(); c!=children.end(); c++)
00605     (*c).second->print_constants_doc(fp,prefix+(*c).first+"::");
00606 }
00607 
00608 
00609 
00610 template<class ParamT>
00611 void ParameterMap<ParamT>::print_parameters_doc(FILE *fp, const string& prefix) const
00612 {
00613   /* Only print separator at top level */
00614   if (prefix=="")
00615     fprintf(fp,"%s\n",help_separator);
00616   
00617   /* Print our data */
00618   for (typename DataType::const_iterator i=data.begin(); i!=data.end(); i++)
00619     if (!(*i).is_constant())
00620       fprintf(fp,"%s%s\n",(*i).doc_string(prefix).c_str(),help_separator);
00621 
00622   /* Print children's data */
00623   for (typename ChildListType::const_iterator c=children.begin(); c!=children.end(); c++)
00624     (*c).second->print_parameters_doc(fp,prefix+(*c).first+"::");
00625 }
00626 
00627 
00628 
00635 template<class ParamT>
00636 char* ParameterMap<ParamT>::completion_generator (char *text, int state) const
00637 {
00638   static int idx, len;
00639 
00640   /*
00641     If this is a new word to complete, initialize the index counters
00642     to the beginning and save the length of text for efficiency
00643   */
00644   if (!state) {
00645     idx = 0;
00646     len = strlen(text);
00647   }
00648   
00649   /* Return the next parameter which partially matches, if any. */
00650   while (idx < int(data.size())) {
00651     const char *name = data[idx++].name().c_str();
00652     if (strncmp (name, text, len) == 0) {
00653       /* Duplicate the name string, as required by readline */
00654       char *newstr = (char *)malloc(strlen(name)+1); assert (newstr);
00655       strcpy (newstr, name);
00656       return (newstr);
00657     }
00658   }
00659   
00660   return ((char *)0); /* No more matches */
00661 }
00662 
00663 
00664 
00665 #endif /* ___PARAMETERMAP_H___ */

Generated on Mon Jan 20 02:35:45 2003 for RF-LISSOM by doxygen1.3-rc2