00001
00007 #ifndef ___PARAMETER_H___
00008 #define ___PARAMETER_H___
00009
00010
00011 #include <stdio.h>
00012 #include <string>
00013 using std::string;
00014
00015 #include "msg.h"
00016 #include "tristate.h"
00017 #include "stringutils.h"
00018 #include "polymorph.h"
00019
00020
00021
00022 #define PARAM_USTRING 0
00023 #define PARAM_3BOOL 1
00024 #define PARAM_INT 2
00025 #define PARAM_DOUBLE 3
00026 #define PARAM_BOOL 4
00027
00028
00029
00030 typedef int cmdstat;
00031
00032 #define SETFN_ARGS2 const string& name, Typeless& param, const Typeless& newvalue
00033 typedef cmdstat (*ParamSetFn2)( SETFN_ARGS2 );
00034
00035
00036 class SetFnWrapper2 {
00037 public:
00038 SetFnWrapper2() { }
00039 virtual ~SetFnWrapper2() { }
00040 virtual cmdstat operator() ( SETFN_ARGS2 )=0;
00041 };
00042
00043
00044 #define SETFN_DECLARE2(fnname) \
00045 cmdstat fnname( SETFN_ARGS2 ); \
00046 struct setfnobj2_ ## fnname : public SetFnWrapper2 { \
00047 cmdstat operator() ( SETFN_ARGS2 ) { \
00048 return fnname(name,param,newvalue); \
00049 } \
00050 }
00051
00052
00054 #define SETFNOBJ_DECLARE2(Owner,fnname) \
00055 cmdstat fnname ( SETFN_ARGS2 ); \
00056 class setfnobj2_ ## fnname : public SetFnWrapper2 { \
00057 Owner* owner; \
00058 public: \
00059 setfnobj2_ ## fnname (Owner* owner_i) : owner(owner_i) { }; \
00060 cmdstat operator() ( SETFN_ARGS2 ) { \
00061 return owner->fnname(name,param,newvalue); \
00062 } \
00063 }; \
00064 friend class setfnobj2_ ## fnname
00065
00066
00067
00079 template <class T=int>
00080 class ParameterDefinition {
00081
00082 public:
00083 typedef ParameterDefinition<T> self;
00084
00086 ParameterDefinition(const Typeless& externallocation, const char *name_i="",
00087 bool is_constant_i=false)
00088 : val_ptr(externallocation.clone(),true),
00089 name_str(name_i), constant(is_constant_i),
00090 been_set(false), doc(0),
00091 low_bound(new Polymorph<int>(0),true), enforce_lower(false),
00092 upp_bound(new Polymorph<int>(0),true), enforce_upper(false),
00093 setfn2(0) { }
00094
00096 ParameterDefinition()
00097 : val_ptr(new Polymorph<int>(0),true),
00098 name_str(""), constant(false),
00099 been_set(false), doc(0),
00100 low_bound(new Polymorph<int>(0),true), enforce_lower(false),
00101 upp_bound(new Polymorph<int>(0),true), enforce_upper(false),
00102 setfn2(0) { }
00103
00104 int check2() const { return check2(datavalue()); }
00105 int check2(const Typeless& val) const;
00106
00107 string usage_string(const string prefix="") const;
00108 string doc_string(const string prefix="") const
00109 { return usage_string(prefix) + (doc? "\n\n" + documentation() : "") + "\n"; }
00110
00111 template <class BT>
00112 self& add_lower_bound(const BT& bound)
00113 { low_bound=PolymorphPtr(new Polymorph<BT>(bound),true); enforce_lower = true; return *this; }
00114
00115 template <class BT>
00116 self& add_upper_bound(const BT& bound)
00117 { upp_bound=PolymorphPtr(new Polymorph<BT>(bound),true); enforce_upper = true; return *this; }
00118
00119
00123 self& add_doc(const char* docstring) { doc=docstring; return *this; }
00124
00128 self& add_default_expr(const string& expr) { default_expr=expr; return *this; }
00129
00139 self& add_setfn(SetFnWrapper2* fnobj) { setfn2 = fnobj; return *this; }
00140
00141 const char * get_default_expr() const { return default_expr!="" ? default_expr.c_str() : 0; }
00142
00149 string stringrep(const Typeless& value, const string& flags="", bool pretty=false) const {
00150 return (pretty?
00151 value.prettyprint( String::StreamFormat(flags)) :
00152 value.stringrep( String::StreamFormat(flags)));
00153 }
00154
00155 string stringrep(const string& flags="", bool pretty=false) const
00156 { return stringrep(datavalue(),flags,pretty); }
00157
00158 void mark_set() { been_set=true; }
00159 bool has_been_set() const { return been_set; }
00160
00161 bool set(const StringParser& parser, const string& s,
00162 bool mark=true, bool verbose=changes_verbose,
00163 const string& prefix="");
00170 void update_default_value(const StringParser& sp) {
00171 if (!has_been_set() && get_default_expr())
00172 set(sp,get_default_expr(),false);
00173 }
00174
00177 bool definition_matches(const self& o) const
00178 { return (name()==o.name() && is_constant()==o.is_constant() &&
00179 datavalue().typestring()==o.datavalue().typestring()); }
00180
00181 bool is_constant() const { return constant; }
00182 bool is_valid() const { return (!name_str.empty() && val_ptr.valueptr()!=0); }
00183
00184 inline const Typeless& datavalue() const { return *val_ptr; }
00185
00186 inline Typeless& datavalue() { return *(val_ptr.valueptr()); }
00187
00188 string print_to_str(const string prefix="") const {
00189
00190 const string rep = String::replace_all(stringrep(datavalue(),"",true),string("$"),string("$$$$"));
00191 return ("set " + prefix + name() + "=" + rep);
00192 }
00193
00194 const string& name() const { return name_str; }
00195
00197 bool operator<(const self& o) const { return( name() < o.name()); }
00198
00199 static void message(Msg::MessageLevel m, const string& s)
00200 { if (mhp && *mhp) (**mhp)(m,s); }
00201
00202 static bool changes_verbose;
00206 self* duplicate() const {
00207 self* o = new self(*this);
00208 o->val_ptr = PolymorphPtr((*val_ptr).duplicate());
00209 return o;
00210 };
00211
00212 private:
00213 static Msg::LevelHandler<>** mhp;
00214
00215 typedef OwningPointer<Typeless,CopyUsingClone<Typeless> > PolymorphPtr;
00216
00217 PolymorphPtr val_ptr;
00218 string name_str;
00219 bool constant;
00220 string default_expr;
00221 int been_set;
00222 const char *doc;
00223 PolymorphPtr low_bound;
00224 int enforce_lower;
00225 PolymorphPtr upp_bound;
00226 int enforce_upper;
00227 SetFnWrapper2* setfn2;
00229 string documentation() const;
00230 string type_string() const { return datavalue().typestring(); }
00231 string value_string() const { return stringrep(datavalue(),"",true); }
00232 string range_string() const
00233 { return string("[" + (enforce_lower? stringrep(*low_bound,"",true) : "*") +
00234 "," + (enforce_upper? stringrep(*upp_bound,"",true) : "*") + "]"); }
00235 };
00236
00237
00238
00239
00240 template <class T>
00241 Msg::LevelHandler<>** ParameterDefinition<T>::mhp=&(Msg::LevelHandler<>::default_instance());
00242 template<class T>
00243 bool ParameterDefinition<T>::changes_verbose=true;
00244
00245
00246
00250 template <class T>
00251 bool ParameterDefinition<T>::set(const StringParser& parser, const string& s,
00252 bool mark, bool verbose, const string& prefix)
00253 {
00254 if (!is_valid())
00255 return false;
00256
00257 if (is_constant()) {
00258 message(Msg::Error,"Can't change value of symbolic constant "+prefix+name());
00259 return false;
00260 }
00261
00262 Typeless& existing = *(val_ptr.valueptr());
00263 const Typeless* newvalue = (*val_ptr).parse(parser,s);
00264
00265 if (check2(*newvalue))
00266 return false;
00267
00268 if (mark) mark_set();
00269
00270 bool status=true;
00271
00272
00273 const string originalrep = stringrep();
00274 if (setfn2) status = ((*setfn2)(name(),existing, *newvalue)>=0);
00275 else existing.set(*newvalue);
00276
00277 if (verbose && !(stringrep() == originalrep))
00278 message(Msg::Notify,"Changed parameter " + prefix + name() + " to " + stringrep("",true) + "");
00279
00280 return true;
00281 }
00282
00283
00284
00289 template <class T>
00290 int ParameterDefinition<T>::check2(const Typeless& value) const
00291 {
00292 if (enforce_lower && value < *low_bound ) {
00293 message(Msg::Error,name()+" too small (" + value.stringrep() +
00294 " < " + (*low_bound).stringrep() + ")");
00295 return 1;
00296 }
00297
00298 if (enforce_upper && value > *upp_bound) {
00299 message(Msg::Error,name()+" too large (" + value.stringrep() +
00300 " > " + (*upp_bound).stringrep() + ")");
00301 return 1;
00302 }
00303
00304 return 0;
00305 }
00306
00307
00308
00309 template <class T>
00310 string ParameterDefinition<T>::usage_string(const string prefix) const
00311 {
00312 const int colpos = 40;
00313 const string column1 = prefix+name()+"="+value_string()
00314 + (get_default_expr()? " [default: " + default_expr + "] " : string(" "));
00315
00316 const string spaces(std::max(0,int((colpos-1)-column1.length())),' ');
00317 const string column2 =
00318 "(" + type_string() +
00319 (constant? " constant" :
00320 (enforce_lower || enforce_upper ?
00321 " with range " + range_string() : "")) + ")";
00322
00323 return column1 + spaces + column2;
00324 }
00325
00326
00327
00329 template <class T>
00330 string ParameterDefinition<T>::documentation() const
00331 {
00332 string s = doc;
00333 unsigned pos;
00334 const string namemarker="%s";
00335 while ((pos=s.find(namemarker))<s.length())
00336 s.replace(pos,namemarker.length(),name());
00337 return s;
00338 }
00339
00340
00341
00342 #endif