diff options
Diffstat (limited to 'src/ConfigBase.hpp')
| -rw-r--r-- | src/ConfigBase.hpp | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/src/ConfigBase.hpp b/src/ConfigBase.hpp new file mode 100644 index 0000000..5e2a50f --- /dev/null +++ b/src/ConfigBase.hpp @@ -0,0 +1,283 @@ +#ifndef CONFIGBASE +#define CONFIGBASE + +#include <QString> +#include <QStringList> +#include <QList> +#include <QMap> + +#include <exception> +#include <type_traits> +#include <limits> + +using CRSMConfigException = std::logic_error; + +namespace CRSMConfigValueType { +enum Type { + None, + String, + Integer, + Boolean, + List, + Map +}; +} + +class CRSMConfigValueBase { +public: + + virtual void setValue(const QString&) { } + virtual QString value() { return ""; } + virtual CRSMConfigValueType::Type type() { return CRSMConfigValueType::Type::None; } + + + + template<typename Type> + static Type getValue(const QString& value); + + template<typename Type> + static QString getStringValue(Type val); +}; + +template<typename Type, typename = void> +class CRSMConfigValue : public CRSMConfigValueBase { +public: +// CRSMConfigValue(Type&) { } + + virtual void setValue(const QString&) { throw CRSMConfigException("Cannot assign"); } + virtual QString value() { throw CRSMConfigException("Cannot get the value"); } +}; + +using String = QString; +using Integer = int; +using Port = ushort; +using Boolean = bool; +#define List(Type) QList<Type> +#define Map(KeyType, ValueType) QMap<KeyType, ValueType> + + +#define ConfigValue(Value) {#Value, mkConfigValue(Value)} +#define ConfigValueEx(Value, ...) {#Value, mkConfigValue(Value, __VA_ARGS__)} + +template<> +class CRSMConfigValue<String> : public CRSMConfigValueBase { + String& config; + bool trimmedQuotes = false; + +public: + CRSMConfigValue(String& config) : config(config) { } + + virtual void setValue(const QString& value) { config = trimQuotes(QString(value), trimmedQuotes); } + virtual QString value() + { + if(trimmedQuotes) + { + return "\"" + config + "\""; + } + else + { + return config; + } + } + virtual CRSMConfigValueType::Type type() { return CRSMConfigValueType::Type::String; } + +private: + QString& trimQuotes(QString&& string, bool& trimmed) + { + trimmed = false; + if(string.length() >= 2 && string.at(0) == '"' && string.at(string.length() - 1) == '"') + { + string.remove(0, 1); + string.remove(string.length() - 1, 1); + trimmed = true; + } + return string; + } + +}; + +template<typename Type> +class CRSMConfigValue<Type, typename std::enable_if<std::is_integral<Type>::value>::type> : public CRSMConfigValueBase { + Type& config; + +public: + CRSMConfigValue(Type& config) : config(config) { } + + virtual void setValue(const QString& value) + { + bool ok = true; + long long longLongVal = value.toLongLong(&ok, 0); + if(!ok) throw CRSMConfigException("\"" + value.toStdString() + "\" could not be parsed as an Integer"); + if(longLongVal < std::numeric_limits<Type>::min() || longLongVal > std::numeric_limits<Type>::max()) throw CRSMConfigException((QString::number(longLongVal) + " is out of range (" + QString::number(std::numeric_limits<Type>::min()) + " - " + QString::number(std::numeric_limits<Type>::max()) + ")").toStdString()); + config = static_cast<Type>(longLongVal); + } + virtual QString value() { return QString::number(config); } + virtual CRSMConfigValueType::Type type() { return CRSMConfigValueType::Type::Integer; } +}; + +template<> +class CRSMConfigValue<Boolean> : public CRSMConfigValueBase { + Boolean& config; + +public: + CRSMConfigValue(Boolean& config) : config(config) { } + + virtual void setValue(const QString& value) + { + if(value == "true") + { + config = true; + } + else if(value == "false") + { + config = false; + } + else + { + throw CRSMConfigException("\"" + value.toStdString() + "\" could not be parsed as a Boolean"); + } + } + virtual QString value() { return config ? "true" : "false"; } + virtual CRSMConfigValueType::Type type() { return CRSMConfigValueType::Type::Boolean; } +}; + +class CRSMConfigValueList : public CRSMConfigValueBase { +public: + virtual void append(const QString& entry) = 0; + virtual void remove(const QString& entry) = 0; + virtual QStringList getValues() = 0; +}; + +class CRSMConfigValueMap : public CRSMConfigValueBase { +public: + virtual void setKeyValue(const QString& key, const QString& value) = 0; + virtual void remove(const QString& key) = 0; + virtual QMap<QString, QString> getValues() = 0; +}; + +template<typename Type> +class CRSMConfigValue<QList<Type>> : public CRSMConfigValueList { + using ListType = QList<Type>; + + ListType& config; + const bool deduplicate; + +public: + CRSMConfigValue(ListType& config, bool deduplicate = true) : config(config), deduplicate(deduplicate) {} + + virtual ListType& list() { return config; } + virtual CRSMConfigValueType::Type type() { return CRSMConfigValueType::Type::List; } + + virtual void append(const QString &entry) + { + Type val = CRSMConfigValueBase::getValue<Type>(entry); + if(!deduplicate || !config.contains(val)) + { + config.append(val); + } + } + + virtual void remove(const QString &entry) { config.removeAll(CRSMConfigValueBase::getValue<Type>(entry)); } + + virtual QStringList getValues() + { + QStringList ret; + + foreach(Type val, config) + { + ret.append(CRSMConfigValueBase::getStringValue(val)); + } + + return ret; + } +}; + +template<typename KeyType, typename ValueType> +class CRSMConfigValue<QMap<KeyType, ValueType>> : public CRSMConfigValueMap { + using MapType = QMap<KeyType, ValueType>; + + MapType& config; + +public: + CRSMConfigValue(MapType& config) : config(config) {} + + virtual MapType& map() { return config; } + virtual CRSMConfigValueType::Type type() { return CRSMConfigValueType::Type::Map; } + + virtual void setKeyValue(const QString& key, const QString& value) + { + config[CRSMConfigValueBase::getValue<KeyType>(key)] = CRSMConfigValueBase::getValue<ValueType>(value); + } + + virtual QMap<QString, QString> getValues() + { + QMap<QString, QString> ret; + + foreach(KeyType key, config.keys()) + { + ret[CRSMConfigValueBase::getStringValue(key)] = CRSMConfigValueBase::getStringValue(config[key]); + } + + return ret; + } + + virtual void remove(const QString &key) + { + config.remove(CRSMConfigValueBase::getValue<KeyType>(key)); + } +}; + +template<typename Type> +class CRSMConfigValue<Type, typename std::enable_if<std::is_enum<Type>::value>::type> : public CRSMConfigValue<typename std::underlying_type<Type>::type> { + using UndType = typename std::underlying_type<Type>::type; +public: + CRSMConfigValue(Type& config) : CRSMConfigValue<UndType>::CRSMConfigValue((UndType&)config) {} +}; + +template<typename Type, typename... Types> +CRSMConfigValue<Type>* mkConfigValue(Type& Value, Types... values) +{ + return new CRSMConfigValue<Type>(Value, values...); +} + +template<typename Type> +Type CRSMConfigValueBase::getValue(const QString& value) +{ + Type ret; + CRSMConfigValue<Type> val(ret); + val.setValue(value); + return ret; +} + +template<typename Type> +QString CRSMConfigValueBase::getStringValue(Type value) +{ + CRSMConfigValue<Type> val(value); + return val.value(); +} + +class CRSMConfigBase +{ +public: + explicit CRSMConfigBase(QMap<QString, CRSMConfigValueBase*> configValues) : configValues(configValues) {} + + void setConfigValue(const QString& name, const QString& value); + QString getConfigValueLine(const QString& name); + void addConfigListEntry(const QString& name, const QString& value); + void removeConfigMapListEntry(const QString &name, const QString &value); + void setConfigMapValue(const QString& name, const QString& key, const QString& value); + + QString read(const QString& fileName, bool writeDefault = true); + bool write(const QString& fileName); + + void setConfigLine(const QString& line); + +protected: + void addConfigValue(QString name, CRSMConfigValueBase *value); + CRSMConfigValueBase& getConfigValue(const QString &name); + + QMap<QString, CRSMConfigValueBase*> configValues; +}; + +#endif // CONFIGBASE + |
