diff options
Diffstat (limited to 'lib/configuration/configuration.h')
-rw-r--r-- | lib/configuration/configuration.h | 61 |
1 files changed, 31 insertions, 30 deletions
diff --git a/lib/configuration/configuration.h b/lib/configuration/configuration.h index cd3c244..f2de92f 100644 --- a/lib/configuration/configuration.h +++ b/lib/configuration/configuration.h @@ -12,52 +12,44 @@ #include <initializer_list> #include <memory> #include <optional> +#include <source_location> +#include <spdlog/spdlog.h> #include <string> #include <type_traits> #include <unordered_map> #include <variant> -#if defined(__clang__) -#define consumable(X) [[clang::consumable(X)]] -#define return_typestate(X) [[clang::return_typestate(X)]] -#define callable_when(X) [[clang::callable_when(X)]] -#define param_typestate(X) [[clang::param_typestate(X)]] -#else -#define consumable(X) -#define return_typestate(X) -#define callable_when(X) -#define param_typestate(X) -#endif - -typedef std::variant<std::string, int, bool> conf_value_t; +using conf_value_t = std::variant<std::string, int, bool>; template <typename T> -concept concept_value_t = std::is_arithmetic<T>::value || std::is_same<T, bool>::value || std::is_constructible<T, std::string>::value; +concept concept_value_t = std::is_arithmetic_v<T> || std::is_same_v<T, bool> || std::is_constructible_v<T, std::string>; -class consumable(unconsumed) Configuration : private std::unordered_map<std::string, conf_value_t> +class Configuration : private std::unordered_map<std::string, conf_value_t> { friend std::ostream &operator<<(std::ostream &out, const Configuration &obj); public: - return_typestate(unconsumed) Configuration(); - return_typestate(unconsumed) Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> l) noexcept; + using kv_pair = std::pair<std::string, conf_value_t>; + + Configuration(); + Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> p_list) noexcept; Configuration(const Configuration &) = delete; Configuration &operator=(const Configuration &) = delete; - return_typestate(unconsumed) Configuration(Configuration && other param_typestate(unconsumed)) = default; + Configuration(Configuration &&other) = default; Configuration &operator=(Configuration &&) = delete; ~Configuration() = default; - callable_when(unconsumed) void read_file(const std::string &location); - callable_when(unconsumed) void read(std::basic_istream<char> & input); + bool read_file(const std::string &location); + void read(std::basic_istream<char> &input); template <typename T> - callable_when(unconsumed) [[nodiscard]] std::optional<T> value(const char *path) const + [[nodiscard]] std::optional<T> value(const char *path, const std::source_location location = std::source_location::current()) const { if(use_global) { - return instance()->value<T>(path); + return instance()->value<T>(path, location); } if(count(path) == 0) { @@ -68,18 +60,19 @@ public: } template <concept_value_t T> - callable_when(unconsumed) [[nodiscard]] std::optional<T> value(const char *path) const + [[nodiscard]] std::optional<T> value(const char *p_path, const std::source_location location = std::source_location::current()) const { if(use_global) { - return instance()->value<T>(path); + return instance()->value<T>(p_path, location); } - if(this->count(path) == 0) { + if(this->count(p_path) == 0) { + spdlog::warn("requested non-existent configuration value {} at {}:{}", p_path, location.file_name(), location.line()); return std::nullopt; } // path is guaranteed to exist - const auto value = at(path); + const auto value = at(p_path); if(std::holds_alternative<int>(value)) { if constexpr(std::is_arithmetic<T>::value) { @@ -89,9 +82,11 @@ public: } } else if(std::holds_alternative<bool>(value)) { - if constexpr(std::is_constructible<T, bool>::value) { + if constexpr(std::is_constructible_v<T, bool> || std::is_same_v<T, bool>) { return std::get<bool>(value); - } else if constexpr(std::is_constructible<T, const char *>::value) { + } else if constexpr(std::is_arithmetic_v<T>) { + return static_cast<T>(std::get<bool>(value)); + } else if constexpr(std::is_constructible_v<T, const char *>) { return std::get<bool>(value) ? T{ "true" } : T{ "false" }; } @@ -99,7 +94,9 @@ public: auto str = std::get<std::string>(value); try { - if constexpr(std::is_floating_point<T>::value) { + if constexpr(std::is_same_v<T, bool>) { + return (str == "true"); + } else if constexpr(std::is_floating_point<T>::value) { return static_cast<T>(std::stod(str)); } else if constexpr(std::is_arithmetic<T>::value) { return static_cast<T>(std::stol(str)); @@ -121,13 +118,17 @@ public: } template <typename T> - callable_when(unconsumed) T &shortcut(T & /* unused */, const char * /* unused */) const + T &shortcut(T & /* unused */, const char * /* unused */, const std::source_location location = std::source_location::current()) const { return T{}; } + static std::string init_global(const std::string &p_path); static void move_global(std::unique_ptr<Configuration> && conf); +protected: + void insert_or_assign(const kv_pair &pair); + private: static Configuration *instance(); |