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
00048 if (parent) parent->children.erase(name());
00049 for (typename ChildListType::const_iterator c=children.begin(); c!=children.end(); c++)
00050 (*c).second->parent=0;
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
00081
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
00140
00141
00142
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
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
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
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
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
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
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
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
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
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
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
00420
00421
00422
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
00456 for (typename DataType::const_iterator i=data.begin(); i!=data.end(); i++) {
00457
00458 numerrors += (*i).check2();
00459 }
00460
00461
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
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
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
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
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
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
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
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
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
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
00581 for (typename DataType::iterator i=data.begin(); i!=data.end(); i++)
00582 (*i).update_default_value(sp);
00583
00584
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
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
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
00614 if (prefix=="")
00615 fprintf(fp,"%s\n",help_separator);
00616
00617
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
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
00642
00643
00644 if (!state) {
00645 idx = 0;
00646 len = strlen(text);
00647 }
00648
00649
00650 while (idx < int(data.size())) {
00651 const char *name = data[idx++].name().c_str();
00652 if (strncmp (name, text, len) == 0) {
00653
00654 char *newstr = (char *)malloc(strlen(name)+1); assert (newstr);
00655 strcpy (newstr, name);
00656 return (newstr);
00657 }
00658 }
00659
00660 return ((char *)0);
00661 }
00662
00663
00664
00665 #endif