#ifndef CONFIGBASE #define CONFIGBASE #include #include #include #include #include #include #include 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 static Type getValue(const QString& value); template static QString getStringValue(Type val); }; template 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 #define Map(KeyType, ValueType) QMap #define ConfigValue(Value) {#Value, mkConfigValue(Value)} #define ConfigValueEx(Value, ...) {#Value, mkConfigValue(Value, __VA_ARGS__)} template<> class CRSMConfigValue : 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 class CRSMConfigValue::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::min() || longLongVal > std::numeric_limits::max()) throw CRSMConfigException((QString::number(longLongVal) + " is out of range (" + QString::number(std::numeric_limits::min()) + " - " + QString::number(std::numeric_limits::max()) + ")").toStdString()); config = static_cast(longLongVal); } virtual QString value() { return QString::number(config); } virtual CRSMConfigValueType::Type type() { return CRSMConfigValueType::Type::Integer; } }; template<> class CRSMConfigValue : 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 getValues() = 0; }; template class CRSMConfigValue> : public CRSMConfigValueList { using ListType = QList; 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(entry); if(!deduplicate || !config.contains(val)) { config.append(val); } } virtual void remove(const QString &entry) { config.removeAll(CRSMConfigValueBase::getValue(entry)); } virtual QStringList getValues() { QStringList ret; foreach(Type val, config) { ret.append(CRSMConfigValueBase::getStringValue(val)); } return ret; } }; template class CRSMConfigValue> : public CRSMConfigValueMap { using MapType = QMap; 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(key)] = CRSMConfigValueBase::getValue(value); } virtual QMap getValues() { QMap 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(key)); } }; template class CRSMConfigValue::value>::type> : public CRSMConfigValue::type> { using UndType = typename std::underlying_type::type; public: CRSMConfigValue(Type& config) : CRSMConfigValue::CRSMConfigValue((UndType&)config) {} }; template CRSMConfigValue* mkConfigValue(Type& Value, Types... values) { return new CRSMConfigValue(Value, values...); } template Type CRSMConfigValueBase::getValue(const QString& value) { Type ret; CRSMConfigValue val(ret); val.setValue(value); return ret; } template QString CRSMConfigValueBase::getStringValue(Type value) { CRSMConfigValue val(value); return val.value(); } class CRSMConfigBase { public: explicit CRSMConfigBase(QMap 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 configValues; }; #endif // CONFIGBASE