gz-cpp-util 1.3
A c++20 library containing various utilities
settings_manager.hpp
1#pragma once
2
3#include "file_io.hpp"
4#include "exceptions.hpp"
6#include "string/utility.hpp"
7#include "concepts.hpp"
8
9#include <functional>
10#include <iostream>
11#include <stdexcept>
12#include <string>
13#include <set>
14#include <type_traits>
15#include <typeinfo>
16#include <unordered_map>
17#include <variant>
18
19namespace gz {
20
21 template<typename T>
22 concept Number = std::integral<T> || std::floating_point<T>;
23
24 template<typename T>
25 concept NotNumber = !Number<T>;
26
27 /* template<typename T, typename... PackTypes> */
28 /* concept IntegralInPack = std::integral<T> && util::IsInPack<T, PackTypes...>; */
29
30 /* template<typename T, typename... PackTypes> */
31 /* concept FloatingPointInPack = std::floating_point<T> && util::IsInPack<T, PackTypes...>; */
32
33 template<typename T, typename... PackTypes>
34 concept NumberInPack = Number<T> && util::IsInPack<T, PackTypes...>;
35
36 template<typename T, typename... PackTypes>
37 concept NotNumberInPack = NotNumber<T> && util::IsInPack<T, PackTypes...>;
38
39
40
41 enum SettingsManagerAllowedValueTypes {
42 SM_RANGE, SM_LIST,
43 };
44
52 template<StringConvertible... CacheTypes>
54 SettingsManagerAllowedValueTypes type;
55 std::variant<std::vector<std::string>, std::vector<CacheTypes>... > allowedValues;
56 };
68 template<Number T, StringConvertible... CacheTypes>
69 void hasCorrectFormat(SettingsManagerAllowedValues<CacheTypes...>& ab);
70 template<NotNumber T, StringConvertible... CacheTypes>
71 void hasCorrectFormat(SettingsManagerAllowedValues<CacheTypes...>& av);
72 /* template<std::integral T, StringConvertible... CacheTypes> */
73 /* void hasCorrectFormat(SettingsManagerAllowedValues<CacheTypes...>& ab); */
74
78 template<StringConvertible... CacheTypes>
83 std::string filepath;
96 bool insertFallbacks = false;
100 bool readFileOnCreation = false;
104 bool writeFileOnExit = false;
105 /*
106 * @brief A map containing SettingsMangerAllowedValues to restrict values
107 * @details
108 * If allowedValues contains key, its value must be allowed by SettingsMangerAllowedValues struct.
109 * If it is not allowed, any operation that tries to set an invalid value will throw InvalidArgument or be ignored:
110 * - in constructor: always ignored
111 * - in SettingsManager::readFileOnCreation: always ignored
112 * - in SettingsManager::setAllowedValues: always ignored
113 * - in SettingsManager::set: depends on throwExceptionWhenNewValueNotAllowed
114 * @see sm_validity
115 */
116 /* util::unordered_string_map<SettingsManagerAllowedValues<CacheTypes...>> allowedValues; */
121 };
122
123 using SettingsCallbackFunction = std::function<void(const std::string&)>;
124
151 template<StringConvertible... CacheTypes>
153 public:
161 SettingsManager(const SettingsManager&) = delete;
162 SettingsManager& operator=(const SettingsManager&) = delete;
163
174 const std::string& get(const std::string& key) const;
183 template<util::IsInPack<CacheTypes...> T>
184 const T& get(const std::string& key);
185
193 const std::string& getOr(const std::string& key, const std::string& fallback);
194
205 template<util::IsInPack<CacheTypes...> T>
206 const T& getOr(const std::string& key, const T& fallback) requires std::copy_constructible<T>;
207
211 const std::string getCopy(const std::string& key) const;
212
216 template<util::IsInPack<CacheTypes...> T>
217 const T getCopy(const std::string& key);
218
222 const std::string getCopyOr(const std::string& key, const std::string& fallback);
223
227 template<util::IsInPack<CacheTypes...> T>
228 const T getCopyOr(const std::string& key, const T& fallback);
229
243 void set(const std::string& key, const std::string& value);
244
251 template<util::IsInPack<CacheTypes...> T>
252 void set(const std::string& key, const T& value);
263 void addCallbackFunction(const std::string& key, SettingsCallbackFunction callbackFunction);
267 void removeCallbackFunction(const std::string& key);
276 void writeToFile() const;
281 void readFromFile(bool checkValidity=true);
285 std::string toString() const {
286 return gz::toString(settings);
287 };
288
296 template<NumberInPack<std::string, CacheTypes...> T>
297 bool isValueAllowed(const std::string& key, const T& value) const noexcept;
298 /* template<IntegralInPack<std::string, CacheTypes...> T> */
299 /* 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;
302
317 template<util::IsInPack<CacheTypes...> T>
318 void setAllowedValues(const std::string& key, std::vector<T>& allowedValues, SettingsManagerAllowedValueTypes type=SM_LIST);
319 template<util::IsInPack<CacheTypes...> T>
320 void setAllowedValues(const std::string& key, std::vector<T>&& allowedValues, SettingsManagerAllowedValueTypes type=SM_LIST) { setAllowedValues<T>(key, allowedValues, type); };
321
326 void removeAllowedValues(const std::string& key) noexcept;
333 const util::unordered_string_map<std::string>& getSettingsMap() const { return settings; };
334
335 private:
348 template<std::same_as<void> Void, StringConvertible CacheType1, StringConvertible... CacheTypesOther>
349 void initCache();
354 template<std::same_as<void> Void>
355 void initCache() {};
356 std::set<std::string> cacheTypes;
357 util::unordered_string_map<util::unordered_string_map<std::variant<std::monostate, CacheTypes...>>> settingsCache;
358 /* template<StringConvertible T> */
359 /* inline bool isRegisteredType(); */
368 // Allowed Values
374 util::unordered_string_map<SettingsManagerAllowedValues<CacheTypes...>> allowedValues;
375 bool throwExceptionWhenNewValueNotAllowed;
382
383 // Settings
388 bool writeFileOnExit;
389 std::string filepath;
390 };
391}
392
393namespace gz {
394 /* template<StringConvertible... CacheTypes, NumberInPack<std::string, CacheTypes...> T> */
395 /* template<std::integral T, StringConvertible... CacheTypes> */
396 /* void hasCorrectFormat(SettingsManagerAllowedValues<CacheTypes...>& av) { */
397 /* const std::vector<T>* v = nullptr; */
398 /* try { */
399 /* v = &std::get<std::vector<T>>(av.allowedValues); */
400 /* } */
401 /* catch (std::bad_variant_access& e) { */
402 /* throw InvalidType("allowedValues variant does not contain type T", "SettingsManagerAllowedValues::hasCorrectFormat"); */
403 /* } */
404 /* switch (av.type) { */
405 /* case SM_LIST: */
406 /* if (v->empty()) { */
407 /* throw InvalidArgument("Allowed value vector needs to have at least one element when AllowedValueType is SM_LIST, but is empty.", "SettingsManagerAllowedValues::hasCorrectFormat"); */
408 /* } */
409 /* break; */
410 /* case SM_RANGE: */
411 /* static_assert(std::floating_point<T> || std::integral<T>, "Type must be integral or floating point when using SM_RANGE."); */
412 /* std::size_t size = std::get<std::vector<int>>(av.allowedValues).size(); */
413 /* if (size == 2) { */
414 /* v->push_back(static_cast<T>(1)); */
415 /* } */
416 /* else if (size != 3) { */
417 /* throw InvalidArgument("AllowedValueType is SM_RANGE with integral type but allowedValues does not have size 2 or 3.", "SettingsManagerAllowedValues::hasCorrectFormat"); */
418 /* } */
419 /* // check min < max */
420 /* if (v[0] >= v[1]) { */
421 /* throw InvalidArgument("AllowedValueType is SM_RANGE but allowedValues[0] is larger than allowedValues[1].", "SettingsManagerAllowedValues::hasCorrectFormat"); */
422 /* } */
423 /* break; */
424 /* } // switch */
425 /* } */
426
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;
431 try {
432 v = &std::get<std::vector<T>>(av.allowedValues);
433 }
434 catch (std::bad_variant_access& e) {
435 throw InvalidType("allowedValues variant does not contain type T", "SettingsManagerAllowedValues::hasCorrectFormat");
436 }
437 switch (av.type) {
438 case SM_LIST:
439 if (v->empty()) {
440 throw InvalidArgument("Allowed value vector needs to have at least one element when AllowedValueType is SM_LIST, but is empty.", "SettingsManagerAllowedValues::hasCorrectFormat");
441 }
442 break;
443 case SM_RANGE:
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();
446 if (size != 2) {
447 throw InvalidArgument("AllowedValueType is SM_RANGE with floating point type but allowedValues does not have size 2.", "SettingsManagerAllowedValues::hasCorrectFormat");
448 }
449 // check min <= max
450 if (v->at(0) > v->at(1)) {
451 /* throw InvalidArgument("AllowedValueType is SM_RANGE but allowedValues[0] >= allowedValues[1].", "SettingsManagerAllowedValues::hasCorrectFormat"); */
452 throw InvalidArgument("AllowedValueType is SM_RANGE but allowedValues[0]=" + toString(v->at(0)) + " > " + toString(v->at(1)) + "=allowedValues[1].", "SettingsManagerAllowedValues::hasCorrectFormat");
453 }
454 break;
455 } // switch
456 }
457
458 /* template<StringConvertible... CacheTypes, NotNumberInPack<std::string, CacheTypes...> T> */
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;
463 try {
464 v = &std::get<std::vector<T>>(av.allowedValues);
465 }
466 catch (std::bad_variant_access& e) {
467 throw InvalidType("allowedValues variant does not contain type T", "SettingsManagerAllowedValues::hasCorrectFormat");
468 }
469 switch (av.type) {
470 case SM_LIST:
471 if (v->empty()) {
472 throw InvalidArgument("Allowed value vector needs to have at least one element when AllowedValueType is SM_LIST, but is empty.", "SettingsManagerAllowedValues::hasCorrectFormat");
473 }
474 break;
475 case SM_RANGE:
476 throw InvalidArgument("Type must be integral or floating point when using SM_RANGE, but is <" + std::string(typeid(T).name()) + ">");
477 break;
478 } // switch
479 }
480
481
482//
483// SETTINGS MANAGER
484//
485 template<StringConvertible... CacheTypes>
487 insertFallbacks = createInfo.insertFallbacks;
488 writeFileOnExit = createInfo.writeFileOnExit;
489 throwExceptionWhenNewValueNotAllowed = createInfo.throwExceptionWhenNewValueNotAllowed;
490
491 /* allowedValues = std::move(createInfo.allowedValues); */
492 settings = std::move(createInfo.initialValues);
493
494 filepath = createInfo.filepath;
495 if (createInfo.readFileOnCreation) {
496 readFromFile(false);
497 }
498
499 // erase invalid initalValues
500 /* for (auto it = settings.begin(); it != settings.end(); it++) { */
501 /* if (!isValueAllowed<std::string>(it->first, it->second)) { */
502 /* it = settings.erase(it); */
503 /* } */
504 /* } */
505
506 initCache<void, CacheTypes...>();
507 }
508
509 template<StringConvertible... CacheTypes>
511 if (writeFileOnExit) {
512 writeToFile();
513 }
514 }
515
516 template<StringConvertible... CacheTypes>
517 template<std::same_as<void> Void, StringConvertible CacheType1, StringConvertible... CacheTypesOther>
519 cacheTypes.insert(typeid(CacheType1).name());
520 initCache<void, CacheTypesOther...>();
521 }
522
523 /* template<StringConvertible... CacheTypes> */
524 /* template<StringConvertible T> */
525 /* inline bool SettingsManager<CacheTypes...>::isRegisteredType() { */
526 /* return cacheTypes.contains(typeid(T).name()); */
527 /* } */
528
529//
530// GET
531//
532 // REFERENCE
533 template<StringConvertible... CacheTypes>
534 const std::string& SettingsManager<CacheTypes...>::get(const std::string& key) const {
535 if (!settings.contains(key)) {
536 throw InvalidArgument("Invalid key: " + key + "'", "SettingsManager::get");
537 }
538 return settings.at(key);
539 }
540
541 template<StringConvertible... CacheTypes>
542 template<util::IsInPack<CacheTypes...> T>
543 const T& SettingsManager<CacheTypes...>::get(const std::string& key) {
544 static_assert(util::IsInPack<T, CacheTypes...>, "Type T is not in parameter pack CacheTypes...");
545 /* if (!isRegisteredType<T>()) { */
546 /* throw InvalidType("Invalid type: '" + std::string(typeid(T).name()) + "'", "SettingsManager::get"); */
547 /* } */
548 if (!settings.contains(key)) {
549 throw InvalidArgument("Invalid key: '" + key + "'", "SettingsManager::get");
550 }
551 // if not cached -> cache
552 if (!settingsCache[typeid(T).name()].contains(key)) {
553 try {
554 /* settingsCache[typeid(T).name()][key].emplace(fromString<T>(settings[key])); */
555 /* settingsCache[typeid(T).name()][key](fromString<T>(settings[key])); */
556 settingsCache[typeid(T).name()][key] = std::variant<std::monostate, CacheTypes...>(fromString<T>(settings[key]));
557 }
558 catch (...) {
559 throw InvalidType("Could not convert value '" + settings[key] + "' to type '" + std::string(typeid(T).name()) + "'. Key: '" + key + "'", "SettingsManager::get");
560 }
561 }
562 /* std::cout << "get<" << typeid(T).name() << ">\n"; */
563 return std::get<T>(settingsCache[typeid(T).name()][key]);
564 }
565
566
567 // REFERENCE OR FALLBACK
568 template<StringConvertible... CacheTypes>
569 const std::string& SettingsManager<CacheTypes...>::getOr(const std::string& key, const std::string& fallback) {
570 if (settings.contains(key)) {
571 return get(key);
572 }
573 else {
574 if (insertFallbacks) {
575 settings[key] = fallback;
576 }
577 return fallback;
578 }
579 }
580
581 template<StringConvertible... CacheTypes>
582 template<util::IsInPack<CacheTypes...> T>
583 const T& SettingsManager<CacheTypes...>::getOr(const std::string& key, const T& fallback) requires std::copy_constructible<T> {
584 /* if (!isRegisteredType<T>()) { */
585 /* throw InvalidType("Invalid type: '" + std::string(typeid(T).name()) + "'", "SettingsManager::getOr"); */
586 /* } */
587 if (settings.contains(key)) {
588 return get<T>(key);
589 }
590 else {
591 if (insertFallbacks) {
592 try {
593 settings[key] = gz::toString(fallback);
594 }
595 catch (...) {
596 throw InvalidType("Can not convert fallback value to string. Key: '" + key + "'", "SettingsManager::getOr");
597 }
598 /* static_assert(CanInsertTIntoVariant<T, std::monostate, CacheTypes...>, "ERROR: Can not insert T into variant with monostate, CacheTypes..."); */
599 /* settingsCache[typeid(T).name()][key].emplace(fallback); */
600 settingsCache[typeid(T).name()][key] = std::variant<std::monostate, CacheTypes...>(T(fallback));
601 }
602 return fallback;
603 }
604 }
605
606 // COPY
607 template<StringConvertible... CacheTypes>
608 const std::string SettingsManager<CacheTypes...>::getCopy(const std::string& key) const {
609 return get(key);
610 }
611 template<StringConvertible... CacheTypes>
612 template<util::IsInPack<CacheTypes...> T>
613 const T SettingsManager<CacheTypes...>::getCopy(const std::string& key) {
614 return get<T>(key);
615 }
616 // COPY OR FALLBACK
617 template<StringConvertible... CacheTypes>
618 const std::string SettingsManager<CacheTypes...>::getCopyOr(const std::string& key, const std::string& fallback) {
619 return getOr(key, fallback);
620 }
621 template<StringConvertible... CacheTypes>
622 template<util::IsInPack<CacheTypes...> T>
623 const T SettingsManager<CacheTypes...>::getCopyOr(const std::string& key, const T& fallback) {
624 return getOr<T>(key, fallback);
625 }
626
627//
628// SET
629//
630 template<StringConvertible... CacheTypes>
631 void SettingsManager<CacheTypes...>::set(const std::string& key, const std::string& value) {
632 // check if new value is allowed
633 if (!isValueAllowed<std::string>(key, value)) {
634 if (throwExceptionWhenNewValueNotAllowed) {
635 throw InvalidArgument("Value '" + value + "' is not allowed. Key: '" + key + "'", "SettingsManager::set");
636 }
637 else {
638 return;
639 }
640 }
641 // remove old value from cache
642 for (auto& [type, cache] : settingsCache) {
643 if (cache.contains(key)) {
644 cache.erase(key);
645 }
646 }
647 settings[key] = value;
648 // Call the callback, if any
649 if (settingsCallbackFunctions.contains(key)) {
650 try {
651 settingsCallbackFunctions[key](value);
652 }
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");
655 }
656 catch (...) {
657 throw Exception("An exception occured in the callback for changing a value. Key: '" + key + "'", "SettingsManager::set");
658 }
659 }
660 }
661
662 template<StringConvertible... CacheTypes>
663 template<util::IsInPack<CacheTypes...> T>
664 void SettingsManager<CacheTypes...>::set(const std::string& key, const T& value) {
665 /* if (!isRegisteredType<T>()) { */
666 /* throw InvalidType("Invalid type: '" + std::string(typeid(T).name()) + "'", "SettingsManager::set<" + std::string(typeid(T).name()) + ">"); */
667 /* } */
668 // convert to string
669 std::string s;
670 try {
671 s = gz::toString(value);
672 }
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()) + ">");
675 }
676 catch (...) {
677 throw InvalidArgument("Could not convert value to string, an exception occured. Key: '" + key + "'", "SettingsManager::set<" + std::string(typeid(T).name()) + ">");
678 }
679 // check if new value is allowed
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()) + ">");
683 }
684 else {
685 return;
686 }
687 }
688 // remove old value from cache
689 for (auto& [type, cache] : settingsCache) {
690 if (cache.contains(key)) {
691 cache.erase(key);
692 }
693 }
694 // add new value
695 settings[key] = std::move(s);
696 settingsCache[typeid(T).name()][key] = value;
697 // Call the callback, if any
698 if (settingsCallbackFunctions.contains(key)) {
699 try {
700 settingsCallbackFunctions[key](s);
701 }
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()) + ">");
704 }
705 catch (...) {
706 throw Exception("An exception occured in the callback for changing a value. Key: '" + key + "'", "SettingsManager::set<" + std::string(typeid(T).name()) + ">");
707 }
708 }
709 }
710
711//
712// ALLOWED VALUES
713//
714 /* template<StringConvertible... CacheTypes> */
715 /* template<IntegralInPack<std::string, CacheTypes...> T> */
716 /* bool SettingsManager<CacheTypes...>::isValueAllowed(const std::string& key, const T& value) const noexcept { */
717 /* if (!allowedValues.contains(key)) { */
718 /* return true; */
719 /* } */
720 /* const std::vector<T>* av = nullptr; */
721 /* try { */
722 /* av = &std::get<std::vector<T>>(allowedValues.at(key).allowedValues); */
723 /* } */
724 /* catch (std::bad_variant_access&) { */
725 /* return false; */
726 /* } */
727
728 /* switch (allowedValues.at(key).type) { */
729 /* case SM_LIST: { */
730 /* for (auto it = av->begin(); it != av->end(); it++) { */
731 /* if (*it == value) { */
732 /* return true; */
733 /* } */
734 /* } */
735 /* } */
736 /* break; */
737 /* case SM_RANGE: { */
738 /* bool valid = true; */
739 /* // value >= lowest */
740 /* valid &= value >= av->at(0); */
741 /* // value < highest */
742 /* valid &= value < av->at(1); */
743 /* // value == lowest + n * step */
744 /* valid &= (value - av->at(0)) % av->at(2) == 0; */
745 /* return valid; */
746 /* } */
747 /* break; */
748 /* } // switch */
749 /* return false; */
750 /* } */
751
752 template<StringConvertible... CacheTypes>
753 template<NumberInPack<std::string, CacheTypes...> T>
754 bool SettingsManager<CacheTypes...>::isValueAllowed(const std::string& key, const T& value) const noexcept {
755 if (!allowedValues.contains(key)) {
756 return true;
757 }
758 const std::vector<T>* av = nullptr;
759 try {
760 av = &std::get<std::vector<T>>(allowedValues.at(key).allowedValues);
761 }
762 catch (std::bad_variant_access&) {
763 return false;
764 }
765
766 switch (allowedValues.at(key).type) {
767 case SM_LIST: {
768 for (auto it = av->begin(); it != av->end(); it++) {
769 if (*it == value) {
770 return true;
771 }
772 }
773 }
774 break;
775 case SM_RANGE: {
776 bool valid = true;
777 // value >= lowest
778 valid &= value >= av->at(0);
779 // value <= highest
780 valid &= value <= av->at(1);
781 return valid;
782 }
783 break;
784 } // switch
785 return false;
786 }
787 template<StringConvertible... CacheTypes>
788 template<NotNumberInPack<std::string, CacheTypes...> T>
789 bool SettingsManager<CacheTypes...>::isValueAllowed(const std::string& key, const T& value) const noexcept {
790 if (!allowedValues.contains(key)) {
791 return true;
792 }
793 const std::vector<T>* av = nullptr;
794 try {
795 av = &std::get<std::vector<T>>(allowedValues.at(key).allowedValues);
796 }
797 catch (std::bad_variant_access&) {
798 return false;
799 }
800 switch (allowedValues.at(key).type) {
801 case SM_LIST: {
802 for (auto it = av->begin(); it != av->end(); it++) {
803 if (*it == value) {
804 return true;
805 }
806 }
807 }
808 break;
809 case SM_RANGE: {
810 return false;
811 }
812 break;
813 } // switch
814 return false;
815 }
816
817 template<StringConvertible... CacheTypes>
818 template<util::IsInPack<CacheTypes...> T>
819 void SettingsManager<CacheTypes...>::setAllowedValues(const std::string& key, std::vector<T>& allowed_vector, SettingsManagerAllowedValueTypes type) {
820 /* std::cout << "setAllowedValues: " << typeid(std::vector<T>).name() << " - " << typeid(T).name() << "\n"; */
821 SettingsManagerAllowedValues<CacheTypes...> av;
822 av.type = type;
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);
826 // erase the current value if it is no longer allowed
827 if (settingsCache[typeid(T).name()].contains(key)) {
828 /* std::cout << "setAllowedValues <" << typeid(T).name() << ">\n"; */
829 if (!isValueAllowed<T>(key, std::get<T>(settingsCache[typeid(T).name()].at(key)))) {
830 settings.erase(key);
831 settingsCache[typeid(T).name()].erase(key);
832 }
833 }
834 else if (settings.contains(key)) {
835 try {
836 if (!isValueAllowed<T>(key, fromString<T>(settings.at(key)))) {
837 settings.erase(key);
838 }
839 }
840 catch (...) {
841 settings.erase(key);
842 }
843 }
844 }
845
846 template<StringConvertible... CacheTypes>
847 void SettingsManager<CacheTypes...>::removeAllowedValues(const std::string& key) noexcept {
848 allowedValues.erase(key);
849 }
850//
851// CALLBACKS
852//
853 template<StringConvertible... CacheTypes>
854 void SettingsManager<CacheTypes...>::addCallbackFunction(const std::string& key, SettingsCallbackFunction callbackFunction) {
855 settingsCallbackFunctions[key] = callbackFunction;
856 }
857 template<StringConvertible... CacheTypes>
859 settingsCallbackFunctions.erase(key);
860 }
861
862//
863// FILE IO
864//
865 template<StringConvertible... CacheTypes>
867 if (filepath.empty()) {
868 throw InvalidArgument("filename is not set", "writeToFile");
869 }
870 writeKeyValueFile(filepath, settings);
871 }
872
873 template<StringConvertible... CacheTypes>
875 if (filepath.empty()) {
876 throw InvalidArgument("filename is not set", "readFromFile");
877 }
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());
880 if (checkValidity) {
881 // insert only valid values
882 for (auto it = map.begin(); it != map.end(); it++) {
883 if (isValueAllowed<std::string>(it->first, it->second)) {
884 settings.insert(*it);
885 }
886 }
887 }
888 else {
889 settings.insert(map.begin(), map.end());
890 }
891 }
892}
893
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