16#include <unordered_map> 
   22    concept Number = std::integral<T> || std::floating_point<T>;
 
   25    concept NotNumber = !Number<T>;
 
   33    template<
typename T, 
typename... PackTypes>
 
   34    concept NumberInPack = Number<T> && util::IsInPack<T, PackTypes...>;
 
   36    template<
typename T, 
typename... PackTypes>
 
   37    concept NotNumberInPack = NotNumber<T> && util::IsInPack<T, PackTypes...>;
 
   41    enum SettingsManagerAllowedValueTypes {
 
   52    template<StringConvertible... CacheTypes>
 
   54        SettingsManagerAllowedValueTypes type;
 
   55        std::variant<std::vector<std::string>, std::vector<CacheTypes>... > allowedValues;
 
  123    using SettingsCallbackFunction = std::function<void(
const std::string&)>;
 
  174            const std::string& 
get(
const std::string& key) 
const;
 
  184            const T& 
get(
const std::string& key);
 
  193            const std::string& 
getOr(
const std::string& key, 
const std::string& fallback);
 
  206            const T& 
getOr(
const std::string& key, 
const T& fallback) 
requires std::copy_constructible<T>;
 
  211            const std::string 
getCopy(
const std::string& key) 
const;
 
  217            const T 
getCopy(
const std::string& key);
 
  222            const std::string 
getCopyOr(
const std::string& key, 
const std::string& fallback);
 
  228            const T 
getCopyOr(
const std::string& key, 
const T& fallback);
 
  243            void set(
const std::string& key, 
const std::string& value);
 
  252            void set(
const std::string& key, 
const T& value);
 
  263            void addCallbackFunction(
const std::string& key, SettingsCallbackFunction callbackFunction);
 
  276            void writeToFile() 
const;
 
  285            std::string toString()
 const {
 
  296            template<NumberInPack<std::string, CacheTypes...> T>
 
  297            bool isValueAllowed(
const std::string& key, 
const T& value) 
const noexcept;
 
  300            template<NotNumberInPack<std::string, CacheTypes...> T>
 
  301            bool isValueAllowed(
const std::string& key, 
const T& value) 
const noexcept;
 
  318            void setAllowedValues(
const std::string& key, std::vector<T>& allowedValues, SettingsManagerAllowedValueTypes type=SM_LIST);
 
  320            void setAllowedValues(
const std::string& key, std::vector<T>&& allowedValues, SettingsManagerAllowedValueTypes type=SM_LIST) { setAllowedValues<T>(key, allowedValues, type); };
 
  348            template<std::same_as<
void> Vo
id, StringConvertible CacheType1, StringConvertible... CacheTypesOther>
 
  354            template<std::same_as<
void> Vo
id>
 
  356            std::set<std::string> cacheTypes;
 
  375            bool throwExceptionWhenNewValueNotAllowed;
 
  388            bool writeFileOnExit;
 
  389            std::string filepath;
 
  427    template<Number T, StringConvertible... CacheTypes>
 
  428    void hasCorrectFormat(SettingsManagerAllowedValues<CacheTypes...>& av) {
 
  429        static_assert(util::IsInPack<T, CacheTypes...>, 
"T must be be in pack CacheTypes");
 
  430        const std::vector<T>* v = 
nullptr;
 
  432            v = &std::get<std::vector<T>>(av.allowedValues);
 
  434        catch (std::bad_variant_access& e) {
 
  435            throw InvalidType(
"allowedValues variant does not contain type T", 
"SettingsManagerAllowedValues::hasCorrectFormat");
 
  440                    throw InvalidArgument(
"Allowed value vector needs to have at least one element when AllowedValueType is SM_LIST, but is empty.", 
"SettingsManagerAllowedValues::hasCorrectFormat");
 
  444                static_assert(std::floating_point<T> || std::integral<T>, 
"Type must be integral or floating point when using SM_RANGE.");
 
  445                std::size_t size = v->size();
 
  447                    throw InvalidArgument(
"AllowedValueType is SM_RANGE with floating point type but allowedValues does not have size 2.", 
"SettingsManagerAllowedValues::hasCorrectFormat");
 
  450                if (v->at(0) > v->at(1)) {
 
  452                    throw InvalidArgument(
"AllowedValueType is SM_RANGE but allowedValues[0]=" + 
toString(v->at(0)) + 
" > " + 
toString(v->at(1)) + 
"=allowedValues[1].", 
"SettingsManagerAllowedValues::hasCorrectFormat");
 
  459    template<NotNumber T, StringConvertible... CacheTypes>
 
  460    void hasCorrectFormat(SettingsManagerAllowedValues<CacheTypes...>& av) {
 
  461        static_assert(util::IsInPack<T, CacheTypes...>, 
"T must be be in pack CacheTypes");
 
  462        const std::vector<T>* v = 
nullptr;
 
  464            v = &std::get<std::vector<T>>(av.allowedValues);
 
  466        catch (std::bad_variant_access& e) {
 
  467            throw InvalidType(
"allowedValues variant does not contain type T", 
"SettingsManagerAllowedValues::hasCorrectFormat");
 
  472                    throw InvalidArgument(
"Allowed value vector needs to have at least one element when AllowedValueType is SM_LIST, but is empty.", 
"SettingsManagerAllowedValues::hasCorrectFormat");
 
  476                throw InvalidArgument(
"Type must be integral or floating point when using SM_RANGE, but is <" + std::string(
typeid(T).name()) + 
">");
 
  485    template<StringConvertible... CacheTypes>
 
  506        initCache<void, CacheTypes...>();
 
  511        if (writeFileOnExit) {
 
  516    template<StringConvertible... CacheTypes>
 
  517    template<std::same_as<
void> Vo
id, StringConvertible CacheType1, StringConvertible... CacheTypesOther>
 
  519        cacheTypes.insert(
typeid(CacheType1).name());
 
  520        initCache<void, CacheTypesOther...>();
 
  535        if (!settings.contains(key)) {
 
  536            throw InvalidArgument(
"Invalid key: " + key + 
"'", 
"SettingsManager::get");
 
  538        return settings.at(key);
 
  544        static_assert(
util::IsInPack<T, CacheTypes...>, 
"Type T is not in parameter pack CacheTypes...");
 
  548        if (!settings.contains(key)) {
 
  549            throw InvalidArgument(
"Invalid key: '" + key + 
"'", 
"SettingsManager::get");
 
  552        if (!settingsCache[
typeid(T).name()].contains(key)) {
 
  556                settingsCache[
typeid(T).name()][key] = std::variant<std::monostate, CacheTypes...>(fromString<T>(settings[key]));
 
  559                throw InvalidType(
"Could not convert value '" + settings[key] + 
"' to type '" + std::string(
typeid(T).name()) + 
"'. Key: '" + key + 
"'", 
"SettingsManager::get");
 
  563        return std::get<T>(settingsCache[
typeid(T).name()][key]);
 
  570        if (settings.contains(key)) {
 
  574            if (insertFallbacks) {
 
  575                settings[key] = fallback;
 
  587        if (settings.contains(key)) {
 
  591            if (insertFallbacks) {
 
  596                    throw InvalidType(
"Can not convert fallback value to string. Key: '" + key + 
"'", 
"SettingsManager::getOr");
 
  600                settingsCache[
typeid(T).name()][key] = std::variant<std::monostate, CacheTypes...>(T(fallback));
 
  619        return getOr(key, fallback);
 
  624        return getOr<T>(key, fallback);
 
  633        if (!isValueAllowed<std::string>(key, value)) {
 
  634            if (throwExceptionWhenNewValueNotAllowed) {
 
  635                throw InvalidArgument(
"Value '" + value + 
"' is not allowed. Key: '" + key + 
"'", 
"SettingsManager::set");
 
  642        for (
auto& [type, cache] : settingsCache) {
 
  643            if (cache.contains(key)) {
 
  647        settings[key] = value;
 
  649        if (settingsCallbackFunctions.contains(key)) {
 
  651                settingsCallbackFunctions[key](value);
 
  653            catch (std::exception& e) {
 
  654                throw Exception(
"An exception occured in the callback for changing a value: '" + std::string(e.what()) + 
"'. Key: '" + key + 
"'", 
"SettingsManager::set");
 
  657                throw Exception(
"An exception occured in the callback for changing a value. Key: '" + key + 
"'", 
"SettingsManager::set");
 
  673        catch (std::exception& e) {
 
  674            throw InvalidArgument(
"Could not convert value to string, an exception occured: '" + std::string(e.what()) + 
"'. Key: '" + key + 
"'", 
"SettingsManager::set<" + std::string(
typeid(T).name()) + 
">");
 
  677            throw InvalidArgument(
"Could not convert value to string, an exception occured. Key: '" + key + 
"'", 
"SettingsManager::set<" + std::string(
typeid(T).name()) + 
">");
 
  680        if (!isValueAllowed<T>(key, value)) {
 
  681            if (throwExceptionWhenNewValueNotAllowed) {
 
  682                throw InvalidArgument(
"Value '" + s + 
"' is not allowed. Key: '" + key + 
"'", 
"SettingsManager::set<" + std::string(
typeid(T).name()) + 
">");
 
  689        for (
auto& [type, cache] : settingsCache) {
 
  690            if (cache.contains(key)) {
 
  695        settings[key] = std::move(s);
 
  696        settingsCache[
typeid(T).name()][key] = value;
 
  698        if (settingsCallbackFunctions.contains(key)) {
 
  700                settingsCallbackFunctions[key](s);
 
  702            catch (std::exception& e) {
 
  703                throw Exception(
"An exception occured in the callback for changing a value: '" + std::string(e.what()) + 
"'. Key: '" + key + 
"'", 
"SettingsManager::set<" + std::string(
typeid(T).name()) + 
">");
 
  706                throw Exception(
"An exception occured in the callback for changing a value. Key: '" + key + 
"'", 
"SettingsManager::set<" + std::string(
typeid(T).name()) + 
">");
 
  753    template<NumberInPack<std::string, CacheTypes...> T>
 
  755        if (!allowedValues.contains(key)) {
 
  758        const std::vector<T>* av = 
nullptr;
 
  760            av = &std::get<std::vector<T>>(allowedValues.at(key).allowedValues);
 
  762        catch (std::bad_variant_access&) {
 
  766        switch (allowedValues.at(key).type) {
 
  768                for (
auto it = av->begin(); it != av->end(); it++) {
 
  778                valid &= value >= av->at(0);
 
  780                valid &= value <= av->at(1);
 
  788    template<NotNumberInPack<std::string, CacheTypes...> T>
 
  790        if (!allowedValues.contains(key)) {
 
  793        const std::vector<T>* av = 
nullptr;
 
  795            av = &std::get<std::vector<T>>(allowedValues.at(key).allowedValues);
 
  797        catch (std::bad_variant_access&) {
 
  800        switch (allowedValues.at(key).type) {
 
  802                for (
auto it = av->begin(); it != av->end(); it++) {
 
  817    template<StringConvertible... CacheTypes>
 
  818    template<util::IsInPack<CacheTypes...> T>
 
  823        av.allowedValues = std::variant<std::vector<std::string>, std::vector<CacheTypes>...>(std::move(allowed_vector));
 
  824        hasCorrectFormat<T>(av);
 
  825        allowedValues[key] = std::move(av);
 
  827        if (settingsCache[
typeid(T).name()].contains(key)) {
 
  829            if (!isValueAllowed<T>(key, std::get<T>(settingsCache[
typeid(T).name()].at(key)))) {
 
  831                settingsCache[
typeid(T).name()].erase(key);
 
  834        else if (settings.contains(key)) {
 
  836                if (!isValueAllowed<T>(key, fromString<T>(settings.at(key)))) {
 
  848        allowedValues.erase(key);
 
  855        settingsCallbackFunctions[key] = callbackFunction;
 
  859        settingsCallbackFunctions.erase(key);
 
  867        if (filepath.empty()) {
 
  870        writeKeyValueFile(filepath, settings);
 
  873    template<StringConvertible... CacheTypes>
 
  875        if (filepath.empty()) {
 
  878        std::unordered_map<std::string, std::string> map = readKeyValueFile<std::unordered_map<std::string, std::string>>(filepath);
 
  879        settings.insert(map.begin(), map.end());
 
  882            for (
auto it = map.begin(); it != map.end(); it++) {
 
  883                if (isValueAllowed<std::string>(it->first, it->second)) {
 
  884                    settings.insert(*it);
 
  889            settings.insert(map.begin(), map.end());
 
The parent for all other exceptions.
Definition: exceptions.hpp:11
 
Any error that implies an invalid argument was passed to a function.
Definition: exceptions.hpp:33
 
Any error where a wrong type was used.
Definition: exceptions.hpp:43
 
Definition: settings_manager.hpp:152
 
bool isValueAllowed(const std::string &key, const T &value) const noexcept
Check if a value is allowed for key.
Definition: settings_manager.hpp:754
 
SettingsManager(SettingsManagerCreateInfo< CacheTypes... > &createInfo)
Create a SettingsManager.
Definition: settings_manager.hpp:486
 
const std::string & get(const std::string &key) const
Get a reference to a value.
Definition: settings_manager.hpp:534
 
void setAllowedValues(const std::string &key, std::vector< T > &allowedValues, SettingsManagerAllowedValueTypes type=SM_LIST)
Set the allowed values for a key.
Definition: settings_manager.hpp:819
 
void initAllowedValues()
Make sure the allowedValues map is valid.
 
const std::string getCopyOr(const std::string &key, const std::string &fallback)
Same as getOr, but returns a copy of value and not a const reference.
Definition: settings_manager.hpp:618
 
void initCache()
Recursive initialitation of the cache.
Definition: settings_manager.hpp:518
 
void addCallbackFunction(const std::string &key, SettingsCallbackFunction callbackFunction)
Add a callback function that gets called when the the value to key is changed with set.
Definition: settings_manager.hpp:854
 
void removeCallbackFunction(const std::string &key)
Remove the callback function for key.
Definition: settings_manager.hpp:858
 
void removeAllowedValues(const std::string &key) noexcept
Remove allowed values for key. All values are allowed afterwards.
Definition: settings_manager.hpp:847
 
const util::unordered_string_map< std::string > & getSettingsMap() const
Get a const reference to the underlying map.
Definition: settings_manager.hpp:333
 
const std::string & getOr(const std::string &key, const std::string &fallback)
Get a reference to the value, or return the fallback if the setting is not present.
Definition: settings_manager.hpp:569
 
void readFromFile(bool checkValidity=true)
Read the contents from the provided filepath.
Definition: settings_manager.hpp:874
 
bool insertFallbacks
Add fallback to values if key is not present when using getOr.
Definition: settings_manager.hpp:387
 
void initCache()
End for the recursive cache initialization.
Definition: settings_manager.hpp:355
 
const std::string getCopy(const std::string &key) const
Same as get, but returns a copy of value and not a const reference.
Definition: settings_manager.hpp:608
 
void set(const std::string &key, const std::string &value)
Set the value of key to value.
Definition: settings_manager.hpp:631
 
gz::toString and gz::fromString overloads exist
Definition: conversion.hpp:211
 
Satisfied when T is in PackTypes.
Definition: concepts.hpp:9
 
Concepts that might be useful elsewhere.
 
Contains utilities for type conversions to and from string.
 
Contains exceptions used in this library.
 
Contains file reading/writing utility.
 
Information about the allowed values.
Definition: settings_manager.hpp:53
 
Creation info for SettingsManager.
Definition: settings_manager.hpp:79
 
bool readFileOnCreation
Wether to load values from filepath when creating the SettingsManager.
Definition: settings_manager.hpp:100
 
bool insertFallbacks
Wether to insert a fallback, when no value is present.
Definition: settings_manager.hpp:96
 
util::unordered_string_map< std::string > initialValues
(Optional) Map containing default values.
Definition: settings_manager.hpp:89
 
bool throwExceptionWhenNewValueNotAllowed
Wether to throw an exception when trying to set an invalid value.
Definition: settings_manager.hpp:120
 
std::string filepath
(Optional) Path to the file containing the settings
Definition: settings_manager.hpp:83
 
bool writeFileOnExit
Wether to write the values to filepath when destroying the SettingsManager.
Definition: settings_manager.hpp:104
 
std::string toString(const T &s)
Declaration of toString in global namespace, so that concepts can use it.
 
Contains utility for strings.
 
std::unordered_map< std::string, T, util::string_hash, std::equal_to<> > unordered_string_map
A unordered_map where you can use string_views to access elements.
Definition: utility.hpp:62