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