2013-04-13 17:55:33 +03:00
|
|
|
#ifndef _library__settingvar__hpp__included__
|
|
|
|
#define _library__settingvar__hpp__included__
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <map>
|
|
|
|
#include <set>
|
|
|
|
#include "threadtypes.hpp"
|
|
|
|
#include "string.hpp"
|
|
|
|
#include <string>
|
|
|
|
|
2013-12-20 10:30:50 +02:00
|
|
|
namespace settingvar
|
|
|
|
{
|
|
|
|
class base;
|
|
|
|
class group;
|
|
|
|
class description;
|
2013-04-13 17:55:33 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A settings listener.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
struct listener
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Destructor.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
virtual ~listener() throw();
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Listen for setting changing value.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
virtual void on_setting_change(group& _group, const base& val) = 0;
|
2013-04-13 17:55:33 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Group of setting variables.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
class group
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
group() throw(std::bad_alloc);
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Destructor.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
~group() throw();
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Get all settings.
|
|
|
|
*/
|
|
|
|
std::set<std::string> get_settings_set() throw(std::bad_alloc);
|
|
|
|
/**
|
|
|
|
* Get setting.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
base& operator[](const std::string& name);
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Add a listener.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
void add_listener(struct listener& _listener) throw(std::bad_alloc);
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Remove a listener.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
void remove_listener(struct listener& _listener) throw(std::bad_alloc);
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Register a setting.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
void do_register(const std::string& name, base& _setting) throw(std::bad_alloc);
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Unregister a setting.
|
|
|
|
*/
|
|
|
|
void do_unregister(const std::string& name) throw(std::bad_alloc);
|
|
|
|
/**
|
|
|
|
* Fire listener.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
void fire_listener(base& var) throw();
|
2013-04-13 17:55:33 +03:00
|
|
|
private:
|
2013-12-20 10:30:50 +02:00
|
|
|
std::map<std::string, class base*> settings;
|
|
|
|
std::set<struct listener*> listeners;
|
2013-04-13 17:55:33 +03:00
|
|
|
mutex_class lock;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write-trough value cache.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
class cache
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
cache(group& grp);
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Enumerate contents.
|
|
|
|
*
|
|
|
|
* Note: This reads cached values in perference to actual values.
|
|
|
|
*/
|
|
|
|
std::map<std::string, std::string> get_all();
|
|
|
|
/**
|
|
|
|
* Enumerate valid keys.
|
|
|
|
*
|
|
|
|
* Returns: The set of actually valid keys.
|
|
|
|
*/
|
|
|
|
std::set<std::string> get_keys();
|
|
|
|
/**
|
|
|
|
* Set a value.
|
|
|
|
*
|
|
|
|
* Parameter name: Name of the setting.
|
|
|
|
* Parameter value: New value for the setting.
|
|
|
|
* Parameter allow_invalid: Cache value if invalid, instead of throwing.
|
|
|
|
* Throws std::runtime_error: Failed to set the setting and invalid values not allowed.
|
|
|
|
*
|
|
|
|
* Note: If setting has cached value and setting it succeeds, the cached value is cleared.
|
|
|
|
*/
|
|
|
|
void set(const std::string& name, const std::string& value, bool allow_invalid = false) throw(std::bad_alloc,
|
|
|
|
std::runtime_error);
|
|
|
|
/**
|
|
|
|
* Get a value.
|
|
|
|
*
|
|
|
|
* Parameter name: Name of the setting.
|
|
|
|
* Return: Actual value of the setting.
|
|
|
|
* Throws std::runtime_error: Setting doesn't exist.
|
|
|
|
*/
|
|
|
|
std::string get(const std::string& name) throw(std::bad_alloc, std::runtime_error);
|
2013-05-17 15:25:33 +03:00
|
|
|
/**
|
|
|
|
* Get descriptor for.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
const description& get_description(const std::string& name) throw(std::bad_alloc,
|
2013-05-17 15:25:33 +03:00
|
|
|
std::runtime_error);
|
2013-04-13 17:55:33 +03:00
|
|
|
private:
|
2013-12-20 10:30:50 +02:00
|
|
|
group& grp;
|
2013-04-13 17:55:33 +03:00
|
|
|
mutex_class lock;
|
|
|
|
std::map<std::string, std::string> badcache;
|
|
|
|
};
|
|
|
|
|
2013-05-17 17:22:24 +03:00
|
|
|
/**
|
|
|
|
* Enumeration.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
struct enumeration
|
2013-05-17 17:22:24 +03:00
|
|
|
{
|
2013-12-20 10:30:50 +02:00
|
|
|
enumeration(std::initializer_list<const char*> v)
|
2013-05-17 17:22:24 +03:00
|
|
|
{
|
|
|
|
unsigned x = 0;
|
|
|
|
for(auto i : v) {
|
|
|
|
values[bound = x++] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::string get(unsigned val) { return values.count(val) ? values[val] : ""; }
|
|
|
|
unsigned max_val() { return bound; }
|
|
|
|
private:
|
|
|
|
std::map<unsigned, std::string> values;
|
|
|
|
unsigned bound;
|
|
|
|
};
|
|
|
|
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Description of setting.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
struct description
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
2013-05-17 15:25:33 +03:00
|
|
|
enum _type
|
|
|
|
{
|
|
|
|
T_BOOLEAN,
|
|
|
|
T_NUMERIC,
|
|
|
|
T_STRING,
|
2013-05-17 17:22:24 +03:00
|
|
|
T_PATH,
|
|
|
|
T_ENUMERATION
|
2013-05-17 15:25:33 +03:00
|
|
|
};
|
|
|
|
_type type;
|
|
|
|
int64_t min_val;
|
|
|
|
int64_t max_val;
|
2013-12-20 10:30:50 +02:00
|
|
|
enumeration* _enumeration;
|
2013-04-13 17:55:33 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the description.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
template<class T> static class description& description_get(T dummy);
|
2013-04-13 17:55:33 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Setting variable.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
class base
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
base(group& _group, const std::string& iname, const std::string& hname)
|
2013-04-13 17:55:33 +03:00
|
|
|
throw(std::bad_alloc);
|
|
|
|
/**
|
|
|
|
* Destructor.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
virtual ~base() throw();
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Set setting.
|
|
|
|
*/
|
|
|
|
virtual void str(const std::string& val) throw(std::runtime_error, std::bad_alloc) = 0;
|
|
|
|
/**
|
|
|
|
* Get setting.
|
|
|
|
*/
|
|
|
|
virtual std::string str() const throw(std::runtime_error, std::bad_alloc) = 0;
|
|
|
|
/**
|
|
|
|
* Get setting name.
|
|
|
|
*/
|
|
|
|
const std::string& get_iname() const throw() { return iname; }
|
|
|
|
const std::string& get_hname() const throw() { return hname; }
|
|
|
|
/**
|
|
|
|
* Get setting description.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
virtual const description& get_description() const throw() = 0;
|
2013-04-13 17:55:33 +03:00
|
|
|
protected:
|
2013-12-20 10:30:50 +02:00
|
|
|
base(const base&);
|
|
|
|
base& operator=(const base&);
|
|
|
|
group& sgroup;
|
2013-04-13 17:55:33 +03:00
|
|
|
std::string iname;
|
|
|
|
std::string hname;
|
|
|
|
mutable mutex_class lock;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setting variable.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
template<class model> class variable : public base
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
|
|
|
typedef typename model::valtype_t valtype_t;
|
2013-12-20 10:30:50 +02:00
|
|
|
variable(const variable<model>&);
|
|
|
|
variable<model>& operator=(const variable<model>&);
|
2013-04-13 17:55:33 +03:00
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
variable(group& sgroup, const std::string& iname, const std::string& hname,
|
2013-04-13 17:55:33 +03:00
|
|
|
valtype_t defaultvalue)
|
2013-12-20 10:30:50 +02:00
|
|
|
: base(sgroup, iname, hname)
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
|
|
|
value = defaultvalue;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Destructor.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
virtual ~variable() throw()
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Set setting.
|
|
|
|
*/
|
|
|
|
void str(const std::string& val) throw(std::runtime_error, std::bad_alloc)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
umutex_class h(lock);
|
|
|
|
value = model::read(val);
|
|
|
|
}
|
2013-12-20 10:30:50 +02:00
|
|
|
sgroup.fire_listener(*this);
|
2013-04-13 17:55:33 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get setting.
|
|
|
|
*/
|
|
|
|
std::string str() const throw(std::runtime_error, std::bad_alloc)
|
|
|
|
{
|
|
|
|
umutex_class h(lock);
|
|
|
|
return model::write(value);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Set setting.
|
|
|
|
*/
|
|
|
|
void set(valtype_t _value) throw(std::runtime_error, std::bad_alloc)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
umutex_class h(lock);
|
|
|
|
if(!model::valid(value))
|
|
|
|
throw std::runtime_error("Invalid value");
|
|
|
|
value = _value;
|
|
|
|
}
|
2013-12-20 10:30:50 +02:00
|
|
|
sgroup.fire_listener(*this);
|
2013-04-13 17:55:33 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get setting.
|
|
|
|
*/
|
|
|
|
valtype_t get() throw(std::bad_alloc)
|
|
|
|
{
|
|
|
|
umutex_class h(lock);
|
|
|
|
return model::transform(value);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get setting.
|
|
|
|
*/
|
|
|
|
operator valtype_t()
|
|
|
|
{
|
|
|
|
return get();
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get setting description.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
const description& get_description() const throw()
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
2013-12-20 10:30:50 +02:00
|
|
|
return description_get(dummy);
|
2013-04-13 17:55:33 +03:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
valtype_t value;
|
|
|
|
model dummy;
|
|
|
|
};
|
|
|
|
|
2013-05-17 11:29:34 +03:00
|
|
|
/**
|
|
|
|
* Yes-no.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
struct yes_no
|
2013-05-17 11:29:34 +03:00
|
|
|
{
|
|
|
|
static const char* enable;
|
|
|
|
static const char* disable;
|
|
|
|
};
|
|
|
|
|
2013-04-13 17:55:33 +03:00
|
|
|
/**
|
|
|
|
* Model: Boolean.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
template<typename values> struct model_bool
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
|
|
|
typedef bool valtype_t;
|
|
|
|
static bool valid(bool val) { return true; /* Any boolean is valid boolean. */ }
|
|
|
|
static bool read(const std::string& val)
|
|
|
|
{
|
|
|
|
int x = string_to_bool(val);
|
|
|
|
if(x < 0)
|
|
|
|
throw std::runtime_error("Invalid boolean value");
|
|
|
|
return (x != 0);
|
|
|
|
}
|
|
|
|
static std::string write(bool val)
|
|
|
|
{
|
2013-05-17 11:29:34 +03:00
|
|
|
return val ? values::enable : values::disable;
|
2013-04-13 17:55:33 +03:00
|
|
|
}
|
|
|
|
static bool transform(bool val) { return val; }
|
|
|
|
};
|
|
|
|
|
2013-12-20 10:30:50 +02:00
|
|
|
template<typename values> description& description_get(
|
|
|
|
model_bool<values> X)
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
2013-12-20 10:30:50 +02:00
|
|
|
static description x;
|
2013-05-17 15:25:33 +03:00
|
|
|
static bool init = false;
|
|
|
|
if(!init) {
|
2013-12-20 10:30:50 +02:00
|
|
|
x.type = description::T_BOOLEAN;
|
2013-05-17 15:25:33 +03:00
|
|
|
init = true;
|
|
|
|
}
|
2013-04-13 17:55:33 +03:00
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Model: Integer.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
template<int32_t minimum, int32_t maximum> struct model_int
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
|
|
|
typedef int32_t valtype_t;
|
|
|
|
static bool valid(int32_t val) { return (val >= minimum && val <= maximum); }
|
|
|
|
static int32_t read(const std::string& val)
|
|
|
|
{
|
|
|
|
int x = parse_value<int32_t>(val);
|
|
|
|
if(x < minimum || x > maximum)
|
|
|
|
(stringfmt() << "Value out of range (" << minimum << " to " << maximum << ")").throwex();
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
static std::string write(int32_t val)
|
|
|
|
{
|
|
|
|
return (stringfmt() << val).str();
|
|
|
|
}
|
|
|
|
static int transform(int val) { return val; }
|
|
|
|
};
|
|
|
|
|
2013-12-20 10:30:50 +02:00
|
|
|
template<int32_t m, int32_t M> description& description_get(model_int<m, M> X)
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
2013-12-20 10:30:50 +02:00
|
|
|
static description x;
|
2013-05-17 15:25:33 +03:00
|
|
|
static bool init = false;
|
|
|
|
if(!init) {
|
2013-12-20 10:30:50 +02:00
|
|
|
x.type = description::T_NUMERIC;
|
2013-05-17 15:25:33 +03:00
|
|
|
x.min_val = m;
|
|
|
|
x.max_val = M;
|
|
|
|
init = true;
|
|
|
|
}
|
2013-04-13 17:55:33 +03:00
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Model: Path.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
struct model_path
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
|
|
|
typedef std::string valtype_t;
|
|
|
|
static bool valid(std::string val) { return true; /* Any boolean is valid boolean. */ }
|
|
|
|
static std::string read(const std::string& val)
|
|
|
|
{
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
static std::string write(std::string val)
|
|
|
|
{
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
static std::string transform(std::string val)
|
|
|
|
{
|
|
|
|
return (val != "") ? val : ".";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-12-20 10:30:50 +02:00
|
|
|
template<> description& description_get(model_path X)
|
2013-04-13 17:55:33 +03:00
|
|
|
{
|
2013-12-20 10:30:50 +02:00
|
|
|
static description x;
|
2013-05-17 15:25:33 +03:00
|
|
|
static bool init = false;
|
|
|
|
if(!init) {
|
2013-12-20 10:30:50 +02:00
|
|
|
x.type = description::T_PATH;
|
2013-05-17 15:25:33 +03:00
|
|
|
init = true;
|
|
|
|
}
|
2013-04-13 17:55:33 +03:00
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2013-05-17 17:22:24 +03:00
|
|
|
/**
|
|
|
|
* Model: Enumerated.
|
|
|
|
*/
|
2013-12-20 10:30:50 +02:00
|
|
|
template<enumeration* e> struct model_enumerated
|
2013-05-17 17:22:24 +03:00
|
|
|
{
|
|
|
|
typedef unsigned valtype_t;
|
|
|
|
static bool valid(unsigned val) { return (val <= e->max_val()); }
|
2013-05-17 21:37:53 +03:00
|
|
|
static unsigned read(const std::string& val)
|
2013-05-17 17:22:24 +03:00
|
|
|
{
|
2013-05-17 21:37:53 +03:00
|
|
|
for(unsigned i = 0; i <= e->max_val(); i++)
|
|
|
|
if(val == e->get(i))
|
|
|
|
return i;
|
2013-05-17 17:22:24 +03:00
|
|
|
unsigned x = parse_value<unsigned>(val);
|
|
|
|
if(x > e->max_val())
|
|
|
|
(stringfmt() << "Value out of range (0 to " << e->max_val() << ")").throwex();
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
static std::string write(unsigned val)
|
|
|
|
{
|
2013-05-17 21:37:53 +03:00
|
|
|
return e->get(val);
|
2013-05-17 17:22:24 +03:00
|
|
|
}
|
|
|
|
static int transform(int val) { return val; }
|
|
|
|
};
|
|
|
|
|
2013-12-20 10:30:50 +02:00
|
|
|
template<enumeration* e> description& description_get(model_enumerated<e> X)
|
2013-05-17 17:22:24 +03:00
|
|
|
{
|
2013-12-20 10:30:50 +02:00
|
|
|
static description x;
|
2013-05-17 17:22:24 +03:00
|
|
|
static bool init = false;
|
|
|
|
if(!init) {
|
2013-12-20 10:30:50 +02:00
|
|
|
x.type = description::T_ENUMERATION;
|
|
|
|
x._enumeration = e;
|
2013-05-17 17:22:24 +03:00
|
|
|
init = true;
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
2013-12-20 10:30:50 +02:00
|
|
|
}
|
2013-05-17 17:22:24 +03:00
|
|
|
|
2013-04-13 17:55:33 +03:00
|
|
|
#endif
|