Oops from previous commit
[lsnes.git] / include / library / settingvar.hpp
blob1ef23079bd3d25939e2f282d1f9dffa137372060
1 #ifndef _library__settingvar__hpp__included__
2 #define _library__settingvar__hpp__included__
4 #include <string>
5 #include <map>
6 #include <set>
7 #include "threads.hpp"
8 #include "string.hpp"
9 #include <string>
11 namespace settingvar
13 class base;
14 class group;
15 class description;
16 class set;
17 class superbase;
19 threads::rlock& get_setting_lock();
21 /**
22 * A settings listener.
24 struct listener
26 /**
27 * Destructor.
29 virtual ~listener() throw();
30 /**
31 * Listen for setting changing value.
33 virtual void on_setting_change(group& _group, const base& val) = 0;
36 /**
37 * A set of setting variables.
39 class set
41 public:
42 /**
43 * Set add/drop listener.
45 class listener
47 public:
48 /**
49 * Dtor.
51 virtual ~listener();
52 /**
53 * New item in set.
55 virtual void create(set& s, const std::string& name, superbase& svar) = 0;
56 /**
57 * Deleted item from set.
59 virtual void destroy(set& s, const std::string& name) = 0;
60 /**
61 * Destroyed the entiere set.
63 virtual void kill(set& s) = 0;
65 /**
66 * Create a set.
68 set();
69 /**
70 * Destructor.
72 ~set();
73 /**
74 * Register a supervariable.
76 void do_register(const std::string& name, superbase& info);
77 /**
78 * Unregister a supervariable.
80 void do_unregister(const std::string& name, superbase& info);
81 /**
82 * Add a callback on new supervariable.
84 void add_callback(listener& listener) throw(std::bad_alloc);
85 /**
86 * Drop a callback on new supervariable.
88 void drop_callback(listener& listener);
89 private:
90 char dummy;
93 /**
94 * Group of setting variables.
96 class group
98 public:
99 /**
100 * Constructor.
102 group() throw(std::bad_alloc);
104 * Destructor.
106 ~group() throw();
108 * Get all settings.
110 std::set<std::string> get_settings_set() throw(std::bad_alloc);
112 * Get setting.
114 base& operator[](const std::string& name);
116 * Add a listener.
118 void add_listener(struct listener& _listener) throw(std::bad_alloc);
120 * Remove a listener.
122 void remove_listener(struct listener& _listener) throw(std::bad_alloc);
124 * Register a setting.
126 void do_register(const std::string& name, base& _setting) throw(std::bad_alloc);
128 * Unregister a setting.
130 void do_unregister(const std::string& name, base& _setting) throw(std::bad_alloc);
132 * Fire listener.
134 void fire_listener(base& var) throw();
136 * Add a set of settings.
138 void add_set(set& s) throw(std::bad_alloc);
140 * Remove a set of settings.
142 void drop_set(set& s);
143 private:
145 * Set listener.
147 class xlistener : public set::listener
149 public:
150 xlistener(group& _grp);
151 ~xlistener();
152 void create(set& s, const std::string& name, superbase& sb);
153 void destroy(set& s, const std::string& name);
154 void kill(set& s);
155 private:
156 group& grp;
157 } _listener;
161 * Write-trough value cache.
163 class cache
165 public:
167 * Constructor.
169 cache(group& grp);
171 * Enumerate contents.
173 * Note: This reads cached values in perference to actual values.
175 std::map<std::string, std::string> get_all();
177 * Enumerate valid keys.
179 * Returns: The set of actually valid keys.
181 std::set<std::string> get_keys();
183 * Set a value.
185 * Parameter name: Name of the setting.
186 * Parameter value: New value for the setting.
187 * Parameter allow_invalid: Cache value if invalid, instead of throwing.
188 * Throws std::runtime_error: Failed to set the setting and invalid values not allowed.
190 * Note: If setting has cached value and setting it succeeds, the cached value is cleared.
192 void set(const std::string& name, const std::string& value, bool allow_invalid = false) throw(std::bad_alloc,
193 std::runtime_error);
195 * Get a value.
197 * Parameter name: Name of the setting.
198 * Return: Actual value of the setting.
199 * Throws std::runtime_error: Setting doesn't exist.
201 std::string get(const std::string& name) throw(std::bad_alloc, std::runtime_error);
203 * Get descriptor for.
205 const description& get_description(const std::string& name) throw(std::bad_alloc,
206 std::runtime_error);
208 * Get human-readable name.
210 * Parameter name: Name of the setting.
211 * Return: Human-readable name of the setting.
212 * Throws std::runtime_error: Setting doesn't exist.
214 std::string get_hname(const std::string& name) throw(std::bad_alloc, std::runtime_error);
215 private:
216 group& grp;
217 std::map<std::string, std::string> badcache;
221 * Enumeration.
223 struct enumeration
225 enumeration(std::initializer_list<const char*> v)
227 unsigned x = 0;
228 for(auto i : v) {
229 values[bound = x++] = i;
232 std::string get(unsigned val) { return values.count(val) ? values[val] : ""; }
233 unsigned max_val() { return bound; }
234 private:
235 std::map<unsigned, std::string> values;
236 unsigned bound;
240 * Description of setting.
242 struct description
244 enum _type
246 T_BOOLEAN,
247 T_NUMERIC,
248 T_STRING,
249 T_PATH,
250 T_ENUMERATION
252 _type type;
253 int64_t min_val;
254 int64_t max_val;
255 enumeration* _enumeration;
259 * Get the description.
261 template<class T> static class description& description_get(T dummy);
264 * Supervariable.
266 class superbase
268 public:
270 * Constructor.
272 void _superbase(set& _s, const std::string& iname) throw(std::bad_alloc);
274 * Destructor.
276 virtual ~superbase() throw();
278 * Make a variable.
280 virtual base* make(group& grp) = 0;
282 * Notify set death.
284 void set_died();
285 private:
286 set* s;
287 std::string iname;
291 * Setting variable.
293 class base
295 public:
297 * Constructor.
299 base(group& _group, const std::string& iname, const std::string& hname, bool dynamic) throw(std::bad_alloc);
301 * Destructor.
303 virtual ~base() throw();
305 * Set setting.
307 virtual void str(const std::string& val) throw(std::runtime_error, std::bad_alloc) = 0;
309 * Get setting.
311 virtual std::string str() const throw(std::runtime_error, std::bad_alloc) = 0;
313 * Get setting name.
315 const std::string& get_iname() const throw() { return iname; }
316 const std::string& get_hname() const throw() { return hname; }
318 * Get setting description.
320 virtual const description& get_description() const throw() = 0;
322 * Notify group death.
324 void group_died();
325 protected:
326 base(const base&);
327 base& operator=(const base&);
328 group* sgroup;
329 std::string iname;
330 std::string hname;
331 bool is_dynamic;
335 * Setting variable.
337 template<class model> class variable : public base
339 typedef typename model::valtype_t valtype_t;
340 variable(const variable<model>&);
341 variable<model>& operator=(const variable<model>&);
342 public:
344 * Constructor.
346 variable(group& sgroup, const std::string& iname, const std::string& hname,
347 valtype_t defaultvalue, bool dynamic = false)
348 : base(sgroup, iname, hname, dynamic)
350 value = defaultvalue;
353 * Destructor.
355 virtual ~variable() throw()
359 * Set setting.
361 void str(const std::string& val) throw(std::runtime_error, std::bad_alloc)
364 threads::arlock h(get_setting_lock());
365 value = model::read(val);
367 sgroup->fire_listener(*this);
370 * Get setting.
372 std::string str() const throw(std::runtime_error, std::bad_alloc)
374 threads::arlock h(get_setting_lock());
375 return model::write(value);
378 * Set setting.
380 void set(valtype_t _value) throw(std::runtime_error, std::bad_alloc)
383 threads::arlock h(get_setting_lock());
384 if(!model::valid(value))
385 throw std::runtime_error("Invalid value");
386 value = _value;
388 sgroup->fire_listener(*this);
391 * Get setting.
393 valtype_t get() throw(std::bad_alloc)
395 threads::arlock h(get_setting_lock());
396 return model::transform(value);
399 * Get setting.
401 operator valtype_t()
403 return get();
406 * Get setting description.
408 const description& get_description() const throw()
410 return description_get(dummy);
412 private:
413 valtype_t value;
414 model dummy;
418 * Supervariable with model.
420 template<class model> class supervariable : public superbase
422 typedef typename model::valtype_t valtype_t;
423 supervariable(const supervariable<model>&);
424 supervariable<model>& operator=(const supervariable<model>&);
425 public:
427 * Constructor.
429 supervariable(set& _s, const std::string& _iname, const std::string& _hname, valtype_t _defaultvalue)
430 throw(std::bad_alloc)
431 : s(_s)
433 iname = _iname;
434 hname = _hname;
435 defaultvalue = _defaultvalue;
436 _superbase(_s, iname);
439 * Destructor.
441 ~supervariable() throw()
445 * Make a variable.
447 base* make(group& grp)
449 return new variable<model>(grp, iname, hname, defaultvalue, true);
452 * Read value in instance.
454 valtype_t operator()(group& grp)
456 base* b = &grp[iname];
457 variable<model>* m = dynamic_cast<variable<model>*>(b);
458 if(!m)
459 throw std::runtime_error("No such setting in target group");
460 return m->get();
463 * Write value in instance.
465 void operator()(group& grp, valtype_t val)
467 base* b = &grp[iname];
468 variable<model>* m = dynamic_cast<variable<model>*>(b);
469 if(!m)
470 throw std::runtime_error("No such setting in target group");
471 m->set(val);
473 private:
474 set& s;
475 std::string iname;
476 std::string hname;
477 valtype_t defaultvalue;
481 * Yes-no.
483 struct yes_no
485 static const char* enable;
486 static const char* disable;
490 * Model: Boolean.
492 template<typename values> struct model_bool
494 typedef bool valtype_t;
495 static bool valid(bool val) { return true; /* Any boolean is valid boolean. */ }
496 static bool read(const std::string& val)
498 int x = string_to_bool(val);
499 if(x < 0)
500 throw std::runtime_error("Invalid boolean value");
501 return (x != 0);
503 static std::string write(bool val)
505 return val ? values::enable : values::disable;
507 static bool transform(bool val) { return val; }
510 template<typename values> description& description_get(
511 model_bool<values> X)
513 static description x;
514 static bool init = false;
515 if(!init) {
516 x.type = description::T_BOOLEAN;
517 init = true;
519 return x;
523 * Model: Integer.
525 template<int32_t minimum, int32_t maximum> struct model_int
527 typedef int32_t valtype_t;
528 static bool valid(int32_t val) { return (val >= minimum && val <= maximum); }
529 static int32_t read(const std::string& val)
531 int x = parse_value<int32_t>(val);
532 if(x < minimum || x > maximum)
533 (stringfmt() << "Value out of range (" << minimum << " to " << maximum << ")").throwex();
534 return x;
536 static std::string write(int32_t val)
538 return (stringfmt() << val).str();
540 static int transform(int val) { return val; }
543 template<int32_t m, int32_t M> description& description_get(model_int<m, M> X)
545 static description x;
546 static bool init = false;
547 if(!init) {
548 x.type = description::T_NUMERIC;
549 x.min_val = m;
550 x.max_val = M;
551 init = true;
553 return x;
557 * Model: Path.
559 struct model_path
561 typedef std::string valtype_t;
562 static bool valid(std::string val) { return true; /* Any boolean is valid boolean. */ }
563 static std::string read(const std::string& val)
565 return val;
567 static std::string write(std::string val)
569 return val;
571 static std::string transform(std::string val)
573 return (val != "") ? val : ".";
577 template<> description& description_get(model_path X)
579 static description x;
580 static bool init = false;
581 if(!init) {
582 x.type = description::T_PATH;
583 init = true;
585 return x;
589 * Model: Enumerated.
591 template<enumeration* e> struct model_enumerated
593 typedef unsigned valtype_t;
594 static bool valid(unsigned val) { return (val <= e->max_val()); }
595 static unsigned read(const std::string& val)
597 for(unsigned i = 0; i <= e->max_val(); i++)
598 if(val == e->get(i))
599 return i;
600 unsigned x = parse_value<unsigned>(val);
601 if(x > e->max_val())
602 (stringfmt() << "Value out of range (0 to " << e->max_val() << ")").throwex();
603 return x;
605 static std::string write(unsigned val)
607 return e->get(val);
609 static int transform(int val) { return val; }
612 template<enumeration* e> description& description_get(model_enumerated<e> X)
614 static description x;
615 static bool init = false;
616 if(!init) {
617 x.type = description::T_ENUMERATION;
618 x._enumeration = e;
619 init = true;
621 return x;
625 #endif