From ebfda8b7d4e085dbeb6f028286fa3c217826e019 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:29:14 -0600 Subject: [PATCH] feat: improve settings --- include/REX/REX/INI.h | 38 +- include/REX/REX/JSON.h | 38 +- include/REX/REX/Setting.h | 5 +- include/REX/REX/TOML.h | 38 +- include/SKSE/Impl/PCH.h | 3 +- src/REX/REX.cpp | 1024 +++++++++---------------------------- xmake.lua | 4 +- 7 files changed, 281 insertions(+), 869 deletions(-) diff --git a/include/REX/REX/INI.h b/include/REX/REX/INI.h index 7ca4f4586..2c378b42b 100644 --- a/include/REX/REX/INI.h +++ b/include/REX/REX/INI.h @@ -5,29 +5,21 @@ #ifdef REX_OPTION_INI namespace REX::INI { - namespace detail + namespace Impl { - void StoreLoadImpl(std::string_view& a_fileBase, std::string_view& a_fileUser, std::vector& a_settings); - void StoreSaveImpl(std::string_view& a_fileBase, std::vector& a_settings); template - void SettingLoadImpl(void* a_file, T& a_value, T& a_valueDefault, bool a_useDefault, std::string_view& a_section, std::string_view& a_key); + void SettingLoad(void* a_file, std::string_view a_section, std::string_view a_key, T& a_value, T& a_valueDefault); + template - void SettingSaveImpl(void* a_file, T& a_value, std::string_view& a_section, std::string_view& a_key); + void SettingSave(void* a_file, std::string_view a_section, std::string_view a_key, T& a_value); } class SettingStore : public TSettingStore { public: - virtual void Load() override - { - detail::StoreLoadImpl(m_fileBase, m_fileUser, m_settings); - } - - virtual void Save() override - { - detail::StoreSaveImpl(m_fileBase, m_settings); - } + virtual void Load() override; + virtual void Save() override; }; template @@ -42,19 +34,19 @@ namespace REX::INI {} public: - virtual void Load(void* a_file) override - { - Load(a_file, true); - } - - virtual void Load(void* a_file, bool a_useDefault) override + virtual void Load(void* a_data, bool a_isBase) override { - detail::SettingLoadImpl(a_file, this->m_value, this->m_valueDefault, a_useDefault, m_section, m_key); + if (a_isBase) { + Impl::SettingLoad(a_data, m_section, m_key, this->m_valueDefault, this->m_valueDefault); + this->SetValue(this->m_valueDefault); + } else { + Impl::SettingLoad(a_data, m_section, m_key, this->m_value, this->m_valueDefault); + } } - virtual void Save(void* a_file) override + virtual void Save(void* a_data) override { - detail::SettingSaveImpl(a_file, this->m_value, m_section, m_key); + Impl::SettingSave(a_data, m_section, m_key, this->m_value); } private: diff --git a/include/REX/REX/JSON.h b/include/REX/REX/JSON.h index aa0b2804d..5b64338f6 100644 --- a/include/REX/REX/JSON.h +++ b/include/REX/REX/JSON.h @@ -5,29 +5,21 @@ #ifdef REX_OPTION_JSON namespace REX::JSON { - namespace detail + namespace Impl { - void StoreLoadImpl(std::string_view& a_fileBase, std::string_view& a_fileUser, std::vector& a_settings); - void StoreSaveImpl(std::string_view& a_fileBase, std::vector& a_settings); template - void SettingLoadImpl(void* a_file, T& a_value, T& a_valueDefault, bool a_useDefault, std::string_view& a_path); + void SettingLoad(void* a_file, std::string_view a_path, T& a_value, T& a_valueDefault); + template - void SettingSaveImpl(void* a_file, T& a_value, std::string_view& a_path); + void SettingSave(void* a_file, std::string_view a_path, T& a_value); } class SettingStore : public TSettingStore { public: - virtual void Load() override - { - detail::StoreLoadImpl(m_fileBase, m_fileUser, m_settings); - } - - virtual void Save() override - { - detail::StoreSaveImpl(m_fileBase, m_settings); - } + virtual void Load() override; + virtual void Save() override; }; template @@ -41,19 +33,19 @@ namespace REX::JSON {} public: - virtual void Load(void* a_file) override - { - Load(a_file, true); - } - - virtual void Load(void* a_file, bool a_useDefault) override + virtual void Load(void* a_data, bool a_isBase) override { - detail::SettingLoadImpl(a_file, this->m_value, this->m_valueDefault, a_useDefault, m_path); + if (a_isBase) { + Impl::SettingLoad(a_data, m_path, this->m_valueDefault, this->m_valueDefault); + this->SetValue(this->m_valueDefault); + } else { + Impl::SettingLoad(a_data, m_path, this->m_value, this->m_valueDefault); + } } - virtual void Save(void* a_file) override + virtual void Save(void* a_data) override { - detail::SettingSaveImpl(a_file, this->m_value, m_path); + Impl::SettingSave(a_data, m_path, this->m_value); } private: diff --git a/include/REX/REX/Setting.h b/include/REX/REX/Setting.h index 32618262a..5d26eb572 100644 --- a/include/REX/REX/Setting.h +++ b/include/REX/REX/Setting.h @@ -7,9 +7,8 @@ namespace REX class ISetting { public: - virtual void Load(void* a_file) = 0; - virtual void Load(void* a_file, bool a_useDefault) = 0; - virtual void Save(void* a_file) = 0; + virtual void Load(void* a_data, bool a_isBase) = 0; + virtual void Save(void* a_data) = 0; }; class ISettingStore diff --git a/include/REX/REX/TOML.h b/include/REX/REX/TOML.h index e56f94766..4f08647c9 100644 --- a/include/REX/REX/TOML.h +++ b/include/REX/REX/TOML.h @@ -5,29 +5,21 @@ #ifdef REX_OPTION_TOML namespace REX::TOML { - namespace detail + namespace Impl { - void StoreLoadImpl(std::string_view& a_fileBase, std::string_view& a_fileUser, std::vector& a_settings); - void StoreSaveImpl(std::string_view& a_fileBase, std::vector& a_settings); template - void SettingLoadImpl(void* a_file, T& a_value, T& a_valueDefault, bool a_useDefault, std::string_view& a_path); + void SettingLoad(void* a_file, std::string_view a_path, T& a_value, T& a_valueDefault); + template - void SettingSaveImpl(void* a_file, T& a_value, std::string_view& a_path); + void SettingSave(void* a_file, std::string_view a_path, T& a_value); } class SettingStore : public TSettingStore { public: - virtual void Load() override - { - detail::StoreLoadImpl(m_fileBase, m_fileUser, m_settings); - } - - virtual void Save() override - { - detail::StoreSaveImpl(m_fileBase, m_settings); - } + virtual void Load() override; + virtual void Save() override; }; template @@ -41,19 +33,19 @@ namespace REX::TOML {} public: - virtual void Load(void* a_file) override - { - Load(a_file, true); - } - - virtual void Load(void* a_file, bool a_useDefault) override + virtual void Load(void* a_data, bool a_isBase) override { - detail::SettingLoadImpl(a_file, this->m_value, this->m_valueDefault, a_useDefault, m_path); + if (a_isBase) { + Impl::SettingLoad(a_data, m_path, this->m_valueDefault, this->m_valueDefault); + this->SetValue(this->m_valueDefault); + } else { + Impl::SettingLoad(a_data, m_path, this->m_value, this->m_valueDefault); + } } - virtual void Save(void* a_file) override + virtual void Save(void* a_data) override { - detail::SettingSaveImpl(a_file, this->m_value, m_path); + Impl::SettingSave(a_data, m_path, this->m_value); } private: diff --git a/include/SKSE/Impl/PCH.h b/include/SKSE/Impl/PCH.h index a29bbdd88..042487021 100644 --- a/include/SKSE/Impl/PCH.h +++ b/include/SKSE/Impl/PCH.h @@ -58,7 +58,8 @@ static_assert( std::is_integral_v && sizeof(std::time_t) == sizeof(std::size_t), "wrap std::time_t instead"); -#include "REX/REX.h" +#include "REX/REX/Enum.h" +#include "REX/REX/EnumSet.h" #include "REX/W32/KERNEL32.h" #include "REX/W32/USER32.h" diff --git a/src/REX/REX.cpp b/src/REX/REX.cpp index 79ddb137a..51fdf087b 100644 --- a/src/REX/REX.cpp +++ b/src/REX/REX.cpp @@ -1,844 +1,280 @@ -#include "REX/REX.h" +#include "REX/REX/INI.h" +#include "REX/REX/JSON.h" +#include "REX/REX/TOML.h" #include "SKSE/Logger.h" #ifdef REX_OPTION_INI -# include - -void REX::INI::detail::StoreLoadImpl( - std::string_view& a_fileBase, - std::string_view& a_fileUser, - std::vector& a_settings) -{ - CSimpleIniA ini; - ini.SetUnicode(true); - ini.SetQuotes(true); +#include + +namespace REX::INI +{ + namespace Impl + { + template + void SettingLoad( + void* a_data, + std::string_view a_section, + std::string_view a_key, + T& a_value, + T& a_valueDefault) + { + const auto file = static_cast(a_data); + if (file->contains(a_section.data())) { + auto& section = (*file)[a_section.data()]; + if (section.contains(a_key.data())) { + if constexpr (std::is_same_v) + a_value = section[a_key.data()].as(); + else + a_value = section[a_key.data()].as(); + + return; + } + } - if (ini.LoadFile(a_fileBase.data()) == SI_OK) { - for (auto& setting : a_settings) { - setting->Load(&ini); + a_value = a_valueDefault; } - } - if (ini.LoadFile(a_fileUser.data()) == SI_OK) { - for (auto& setting : a_settings) { - setting->Load(&ini, false); + template void SettingLoad(void*, std::string_view, std::string_view, bool&, bool&); + template void SettingLoad(void*, std::string_view, std::string_view, float&, float&); + template void SettingLoad(void*, std::string_view, std::string_view, double&, double&); + template void SettingLoad(void*, std::string_view, std::string_view, std::uint8_t&, std::uint8_t&); + template void SettingLoad(void*, std::string_view, std::string_view, std::uint16_t&, std::uint16_t&); + template void SettingLoad(void*, std::string_view, std::string_view, std::uint32_t&, std::uint32_t&); + template void SettingLoad(void*, std::string_view, std::string_view, std::int8_t&, std::int8_t&); + template void SettingLoad(void*, std::string_view, std::string_view, std::int16_t&, std::int16_t&); + template void SettingLoad(void*, std::string_view, std::string_view, std::int32_t&, std::int32_t&); + template void SettingLoad(void*, std::string_view, std::string_view, std::string&, std::string&); + + template + void SettingSave( + void* a_data, + std::string_view a_section, + std::string_view a_key, + T& a_value) + { + auto& file = *static_cast(a_data); + if constexpr (std::is_same_v) + file[a_section.data()][a_key.data()] = (char)a_value; + else + file[a_section.data()][a_key.data()] = a_value; } - } -} - -void REX::INI::detail::StoreSaveImpl( - std::string_view& a_fileBase, - std::vector& a_settings) -{ - CSimpleIniA ini; - ini.SetUnicode(true); - ini.SetQuotes(true); - ini.LoadFile(a_fileBase.data()); - for (auto& setting : a_settings) { - setting->Save(&ini); + template void SettingSave(void*, std::string_view, std::string_view, bool&); + template void SettingSave(void*, std::string_view, std::string_view, float&); + template void SettingSave(void*, std::string_view, std::string_view, double&); + template void SettingSave(void*, std::string_view, std::string_view, std::uint8_t&); + template void SettingSave(void*, std::string_view, std::string_view, std::uint16_t&); + template void SettingSave(void*, std::string_view, std::string_view, std::uint32_t&); + template void SettingSave(void*, std::string_view, std::string_view, std::int8_t&); + template void SettingSave(void*, std::string_view, std::string_view, std::int16_t&); + template void SettingSave(void*, std::string_view, std::string_view, std::int32_t&); + template void SettingSave(void*, std::string_view, std::string_view, std::string&); } - ini.SaveFile(a_fileBase.data(), false); -} - -template <> -void REX::INI::detail::SettingLoadImpl( - void* a_file, - bool& a_value, - bool& a_valueDefault, - bool a_useDefault, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - a_value = file->GetBoolValue(a_section.data(), a_key.data(), a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::INI::detail::SettingSaveImpl( - void* a_file, - bool& a_value, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - file->SetBoolValue(a_section.data(), a_key.data(), a_value); -} - -template <> -void REX::INI::detail::SettingLoadImpl( - void* a_file, - float& a_value, - float& a_valueDefault, - bool a_useDefault, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - a_value = static_cast(file->GetDoubleValue(a_section.data(), a_key.data(), a_useDefault ? a_valueDefault : a_value)); -} - -template <> -void REX::INI::detail::SettingSaveImpl( - void* a_file, - float& a_value, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - file->SetDoubleValue(a_section.data(), a_key.data(), a_value); -} - -template <> -void REX::INI::detail::SettingLoadImpl( - void* a_file, - double& a_value, - double& a_valueDefault, - bool a_useDefault, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - a_value = file->GetDoubleValue(a_section.data(), a_key.data(), a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::INI::detail::SettingSaveImpl( - void* a_file, - double& a_value, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - file->SetDoubleValue(a_section.data(), a_key.data(), a_value); -} - -template <> -void REX::INI::detail::SettingLoadImpl( - void* a_file, - std::int8_t& a_value, - std::int8_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - a_value = static_cast(file->GetLongValue(a_section.data(), a_key.data(), a_useDefault ? a_valueDefault : a_value)); -} - -template <> -void REX::INI::detail::SettingSaveImpl( - void* a_file, - std::int8_t& a_value, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - file->SetLongValue(a_section.data(), a_key.data(), a_value); -} - -template <> -void REX::INI::detail::SettingLoadImpl( - void* a_file, - std::int16_t& a_value, - std::int16_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - a_value = static_cast(file->GetLongValue(a_section.data(), a_key.data(), a_useDefault ? a_valueDefault : a_value)); -} - -template <> -void REX::INI::detail::SettingSaveImpl( - void* a_file, - std::int16_t& a_value, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - file->SetLongValue(a_section.data(), a_key.data(), a_value); -} - -template <> -void REX::INI::detail::SettingLoadImpl( - void* a_file, - std::int32_t& a_value, - std::int32_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - a_value = static_cast(file->GetLongValue(a_section.data(), a_key.data(), a_useDefault ? a_valueDefault : a_value)); -} - -template <> -void REX::INI::detail::SettingSaveImpl( - void* a_file, - std::int32_t& a_value, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - file->SetLongValue(a_section.data(), a_key.data(), a_value); -} - -template <> -void REX::INI::detail::SettingLoadImpl( - void* a_file, - std::uint8_t& a_value, - std::uint8_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - a_value = static_cast(file->GetLongValue(a_section.data(), a_key.data(), a_useDefault ? a_valueDefault : a_value)); -} - -template <> -void REX::INI::detail::SettingSaveImpl( - void* a_file, - std::uint8_t& a_value, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - file->SetLongValue(a_section.data(), a_key.data(), a_value); -} - -template <> -void REX::INI::detail::SettingLoadImpl( - void* a_file, - std::uint16_t& a_value, - std::uint16_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - a_value = static_cast(file->GetLongValue(a_section.data(), a_key.data(), a_useDefault ? a_valueDefault : a_value)); -} + void SettingStore::Load() + { + ini::IniFileCaseInsensitive file; -template <> -void REX::INI::detail::SettingSaveImpl( - void* a_file, - std::uint16_t& a_value, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - file->SetLongValue(a_section.data(), a_key.data(), a_value); -} - -template <> -void REX::INI::detail::SettingLoadImpl( - void* a_file, - std::uint32_t& a_value, - std::uint32_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - a_value = static_cast(file->GetLongValue(a_section.data(), a_key.data(), a_useDefault ? a_valueDefault : a_value)); -} - -template <> -void REX::INI::detail::SettingSaveImpl( - void* a_file, - std::uint32_t& a_value, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - file->SetLongValue(a_section.data(), a_key.data(), a_value); -} - -template <> -void REX::INI::detail::SettingLoadImpl( - void* a_file, - std::string& a_value, - std::string& a_valueDefault, - bool a_useDefault, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - a_value = file->GetValue(a_section.data(), a_key.data(), a_useDefault ? a_valueDefault.c_str() : a_value.c_str()); -} - -template <> -void REX::INI::detail::SettingSaveImpl( - void* a_file, - std::string& a_value, - std::string_view& a_section, - std::string_view& a_key) -{ - auto file = static_cast(a_file); - file->SetValue(a_section.data(), a_key.data(), a_value.c_str()); -} -#endif - -#ifdef REX_OPTION_JSON -# include - -void REX::JSON::detail::StoreLoadImpl( - std::string_view& a_fileBase, - std::string_view& a_fileUser, - std::vector& a_settings) -{ - if (std::filesystem::exists(a_fileBase)) { - std::ifstream file{ a_fileBase.data() }; - try { - auto result = nlohmann::json::parse(file); - for (auto setting : a_settings) { - setting->Load(&result); + if (std::filesystem::exists(m_fileBase)) { + file.load(m_fileBase.data()); + for (auto& setting : m_settings) { + setting->Load(&file, true); } - } catch (const std::exception& e) { - SKSE::log::error("{}", e.what()); } - } - if (std::filesystem::exists(a_fileUser)) { - std::ifstream file{ a_fileUser.data() }; - try { - auto result = nlohmann::json::parse(file); - for (auto setting : a_settings) { - setting->Load(&result, false); + if (std::filesystem::exists(m_fileUser)) { + file.load(m_fileUser.data()); + for (auto& setting : m_settings) { + setting->Load(&file, false); } - } catch (const std::exception& e) { - SKSE::log::error("{}", e.what()); } } -} - -void REX::JSON::detail::StoreSaveImpl( - std::string_view& a_fileBase, - std::vector& a_settings) -{ - nlohmann::json output{}; - if (std::filesystem::exists(a_fileBase)) { - std::ifstream file{ a_fileBase.data() }; - output = nlohmann::json::parse(file); - } - - for (auto& setting : a_settings) { - setting->Save(&output); - } - - std::ofstream file{ a_fileBase.data(), std::ios::trunc }; - file << output.dump(4); -} - -template <> -void REX::JSON::detail::SettingLoadImpl( - void* a_file, - bool& a_value, - bool& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - a_value = file->value(a_path, a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::JSON::detail::SettingSaveImpl( - void* a_file, - bool& a_value, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - (*file)[a_path] = a_value; -} - -template <> -void REX::JSON::detail::SettingLoadImpl( - void* a_file, - float& a_value, - float& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - a_value = file->value(a_path, a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::JSON::detail::SettingSaveImpl( - void* a_file, - float& a_value, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - (*file)[a_path] = a_value; -} - -template <> -void REX::JSON::detail::SettingLoadImpl( - void* a_file, - double& a_value, - double& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - a_value = file->value(a_path, a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::JSON::detail::SettingSaveImpl( - void* a_file, - double& a_value, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - (*file)[a_path] = a_value; -} - -template <> -void REX::JSON::detail::SettingLoadImpl( - void* a_file, - std::int8_t& a_value, - std::int8_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - a_value = file->value(a_path, a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::JSON::detail::SettingSaveImpl( - void* a_file, - std::int8_t& a_value, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - (*file)[a_path] = a_value; -} -template <> -void REX::JSON::detail::SettingLoadImpl( - void* a_file, - std::int16_t& a_value, - std::int16_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - a_value = file->value(a_path, a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::JSON::detail::SettingSaveImpl( - void* a_file, - std::int16_t& a_value, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - (*file)[a_path] = a_value; -} - -template <> -void REX::JSON::detail::SettingLoadImpl( - void* a_file, - std::int32_t& a_value, - std::int32_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - a_value = file->value(a_path, a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::JSON::detail::SettingSaveImpl( - void* a_file, - std::int32_t& a_value, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - (*file)[a_path] = a_value; -} - -template <> -void REX::JSON::detail::SettingLoadImpl( - void* a_file, - std::uint8_t& a_value, - std::uint8_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - a_value = file->value(a_path, a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::JSON::detail::SettingSaveImpl( - void* a_file, - std::uint8_t& a_value, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - (*file)[a_path] = a_value; -} - -template <> -void REX::JSON::detail::SettingLoadImpl( - void* a_file, - std::uint16_t& a_value, - std::uint16_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - a_value = file->value(a_path, a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::JSON::detail::SettingSaveImpl( - void* a_file, - std::uint16_t& a_value, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - (*file)[a_path] = a_value; -} - -template <> -void REX::JSON::detail::SettingLoadImpl( - void* a_file, - std::uint32_t& a_value, - std::uint32_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - a_value = file->value(a_path, a_useDefault ? a_valueDefault : a_value); -} - -template <> -void REX::JSON::detail::SettingSaveImpl( - void* a_file, - std::uint32_t& a_value, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - (*file)[a_path] = a_value; -} + void SettingStore::Save() + { + ini::IniFileCaseInsensitive file; -template <> -void REX::JSON::detail::SettingLoadImpl( - void* a_file, - std::string& a_value, - std::string& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - a_value = file->value(a_path, a_useDefault ? a_valueDefault : a_value); -} + file.load(m_fileBase.data()); + for (auto& setting : m_settings) { + setting->Save(&file); + } -template <> -void REX::JSON::detail::SettingSaveImpl( - void* a_file, - std::string& a_value, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - (*file)[a_path] = a_value; + file.save(m_fileBase.data()); + } } #endif -#ifdef REX_OPTION_TOML -# include +#ifdef REX_OPTION_JSON +# include -void REX::TOML::detail::StoreLoadImpl( - std::string_view& a_fileBase, - std::string_view& a_fileUser, - std::vector& a_settings) -{ - try { - auto result = toml::parse_file(a_fileBase); - for (auto& setting : a_settings) { - setting->Load(&result); +namespace REX::JSON +{ + namespace Impl + { + template + void SettingLoad( + void* a_data, + std::string_view a_path, + T& a_value, + T& a_valueDefault) + { + const auto& json = *static_cast(a_data); + if (a_path[0] == '/') + a_value = json.value(nlohmann::json::json_pointer(a_path.data()), a_valueDefault); + else + a_value = json.value(a_path, a_valueDefault); } - } catch (const std::exception& e) { - SKSE::log::error("{}", e.what()); - } - try { - auto result = toml::parse_file(a_fileUser); - for (auto& setting : a_settings) { - setting->Load(&result, false); + template void SettingLoad(void*, std::string_view, bool&, bool&); + template void SettingLoad(void*, std::string_view, float&, float&); + template void SettingLoad(void*, std::string_view, double&, double&); + template void SettingLoad(void*, std::string_view, std::uint8_t&, std::uint8_t&); + template void SettingLoad(void*, std::string_view, std::uint16_t&, std::uint16_t&); + template void SettingLoad(void*, std::string_view, std::uint32_t&, std::uint32_t&); + template void SettingLoad(void*, std::string_view, std::int8_t&, std::int8_t&); + template void SettingLoad(void*, std::string_view, std::int16_t&, std::int16_t&); + template void SettingLoad(void*, std::string_view, std::int32_t&, std::int32_t&); + template void SettingLoad(void*, std::string_view, std::string&, std::string&); + + template + void SettingSave( + void* a_data, + std::string_view a_path, + T& a_value) + { + auto& json = *static_cast(a_data); + if (a_path[0] == '/') + json[nlohmann::json::json_pointer(a_path.data())] = a_value; + else + json[a_path] = a_value; } - } catch (const std::exception& e) { - SKSE::log::error("{}", e.what()); - } -} - -void REX::TOML::detail::StoreSaveImpl( - [[maybe_unused]] std::string_view& a_fileBase, - [[maybe_unused]] std::vector& a_settings) -{ - // toml::parse_result output{}; - // try { - // output = toml::parse_file(a_fileBase); - // } catch (const std::exception& e) { - // // ignore - // } - // - // for (auto& setting : a_settings) { - // setting->Save(&output); - // } - // - // std::ofstream file{ a_fileBase.data(), std::ios::trunc }; - // file << output; -} -template <> -void REX::TOML::detail::SettingLoadImpl( - void* a_file, - bool& a_value, - bool& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - if (auto node = file->at_path(a_path)) { - a_value = node.value_or(a_useDefault ? a_valueDefault : a_value); + template void SettingSave(void*, std::string_view, bool&); + template void SettingSave(void*, std::string_view, float&); + template void SettingSave(void*, std::string_view, double&); + template void SettingSave(void*, std::string_view, std::uint8_t&); + template void SettingSave(void*, std::string_view, std::uint16_t&); + template void SettingSave(void*, std::string_view, std::uint32_t&); + template void SettingSave(void*, std::string_view, std::int8_t&); + template void SettingSave(void*, std::string_view, std::int16_t&); + template void SettingSave(void*, std::string_view, std::int32_t&); + template void SettingSave(void*, std::string_view, std::string&); } -} - -template <> -void REX::TOML::detail::SettingSaveImpl( - [[maybe_unused]] void* a_file, - [[maybe_unused]] bool& a_value, - [[maybe_unused]] std::string_view& a_path) -{ - // auto file = static_cast(a_file); - // file->insert_or_assign(a_path, a_value); -} - -template <> -void REX::TOML::detail::SettingLoadImpl( - void* a_file, - float& a_value, - float& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - if (auto node = file->at_path(a_path)) { - a_value = node.value_or(a_useDefault ? a_valueDefault : a_value); - } -} -template <> -void REX::TOML::detail::SettingSaveImpl( - [[maybe_unused]] void* a_file, - [[maybe_unused]] float& a_value, - [[maybe_unused]] std::string_view& a_path) -{ - // auto file = static_cast(a_file); - // file->insert_or_assign(a_path, a_value); -} + void SettingStore::Load() + { + if (std::filesystem::exists(m_fileBase)) { + std::ifstream file{ m_fileBase.data() }; + try { + auto result = nlohmann::json::parse(file); + for (auto setting : m_settings) { + setting->Load(&result, true); + } + } catch (const std::exception& e) { + SKSE::log::error("{}", e.what()); + } + } -template <> -void REX::TOML::detail::SettingLoadImpl( - void* a_file, - double& a_value, - double& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - if (auto node = file->at_path(a_path)) { - a_value = node.value_or(a_useDefault ? a_valueDefault : a_value); + if (std::filesystem::exists(m_fileUser)) { + std::ifstream file{ m_fileUser.data() }; + try { + auto result = nlohmann::json::parse(file); + for (auto setting : m_settings) { + setting->Load(&result, false); + } + } catch (const std::exception& e) { + SKSE::log::error("{}", e.what()); + } + } } -} - -template <> -void REX::TOML::detail::SettingSaveImpl( - [[maybe_unused]] void* a_file, - [[maybe_unused]] double& a_value, - [[maybe_unused]] std::string_view& a_path) -{ - // auto file = static_cast(a_file); - // file->insert_or_assign(a_path, a_value); -} -template <> -void REX::TOML::detail::SettingLoadImpl( - void* a_file, - std::int8_t& a_value, - std::int8_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - if (auto node = file->at_path(a_path)) { - a_value = node.value_or(a_useDefault ? a_valueDefault : a_value); - } -} - -template <> -void REX::TOML::detail::SettingSaveImpl( - [[maybe_unused]] void* a_file, - [[maybe_unused]] std::int8_t& a_value, - [[maybe_unused]] std::string_view& a_path) -{ - // auto file = static_cast(a_file); - // file->insert_or_assign(a_path, a_value); -} - -template <> -void REX::TOML::detail::SettingLoadImpl( - void* a_file, - std::int16_t& a_value, - std::int16_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - if (auto node = file->at_path(a_path)) { - a_value = node.value_or(a_useDefault ? a_valueDefault : a_value); - } -} + void SettingStore::Save() + { + nlohmann::json output{}; + if (std::filesystem::exists(m_fileBase)) { + std::ifstream file{ m_fileBase.data() }; + output = nlohmann::json::parse(file); + } -template <> -void REX::TOML::detail::SettingSaveImpl( - [[maybe_unused]] void* a_file, - [[maybe_unused]] std::int16_t& a_value, - [[maybe_unused]] std::string_view& a_path) -{ - // auto file = static_cast(a_file); - // file->insert_or_assign(a_path, a_value); -} + for (auto& setting : m_settings) { + setting->Save(&output); + } -template <> -void REX::TOML::detail::SettingLoadImpl( - void* a_file, - std::int32_t& a_value, - std::int32_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - if (auto node = file->at_path(a_path)) { - a_value = node.value_or(a_useDefault ? a_valueDefault : a_value); + std::ofstream file{ m_fileBase.data(), std::ios::trunc }; + file << output.dump(4); } } +#endif -template <> -void REX::TOML::detail::SettingSaveImpl( - [[maybe_unused]] void* a_file, - [[maybe_unused]] std::int32_t& a_value, - [[maybe_unused]] std::string_view& a_path) -{ - // auto file = static_cast(a_file); - // file->insert_or_assign(a_path, a_value); -} +#ifdef REX_OPTION_TOML +# define TOML_EXCEPTIONS 0 +# include -template <> -void REX::TOML::detail::SettingLoadImpl( - void* a_file, - std::uint8_t& a_value, - std::uint8_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - if (auto node = file->at_path(a_path)) { - a_value = node.value_or(a_useDefault ? a_valueDefault : a_value); - } -} +namespace REX::TOML +{ + namespace Impl + { + template + void SettingLoad( + void* a_data, + std::string_view a_path, + T& a_value, + T& a_valueDefault) + { + const auto& table = *static_cast(a_data); + if (const auto node = table[toml::path(a_path)]) + a_value = node.value_or(a_valueDefault); + } -template <> -void REX::TOML::detail::SettingSaveImpl( - [[maybe_unused]] void* a_file, - [[maybe_unused]] std::uint8_t& a_value, - [[maybe_unused]] std::string_view& a_path) -{ - // auto file = static_cast(a_file); - // file->insert_or_assign(a_path, a_value); -} + template void SettingLoad(void*, std::string_view, bool&, bool&); + template void SettingLoad(void*, std::string_view, float&, float&); + template void SettingLoad(void*, std::string_view, double&, double&); + template void SettingLoad(void*, std::string_view, std::uint8_t&, std::uint8_t&); + template void SettingLoad(void*, std::string_view, std::uint16_t&, std::uint16_t&); + template void SettingLoad(void*, std::string_view, std::uint32_t&, std::uint32_t&); + template void SettingLoad(void*, std::string_view, std::int8_t&, std::int8_t&); + template void SettingLoad(void*, std::string_view, std::int16_t&, std::int16_t&); + template void SettingLoad(void*, std::string_view, std::int32_t&, std::int32_t&); + template void SettingLoad(void*, std::string_view, std::string&, std::string&); + + template + void SettingSave( + void* a_data, + std::string_view a_path, + T& a_value) + { + // TODO + } -template <> -void REX::TOML::detail::SettingLoadImpl( - void* a_file, - std::uint16_t& a_value, - std::uint16_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - if (auto node = file->at_path(a_path)) { - a_value = node.value_or(a_useDefault ? a_valueDefault : a_value); + template void SettingSave(void*, std::string_view, bool&); + template void SettingSave(void*, std::string_view, float&); + template void SettingSave(void*, std::string_view, double&); + template void SettingSave(void*, std::string_view, std::uint8_t&); + template void SettingSave(void*, std::string_view, std::uint16_t&); + template void SettingSave(void*, std::string_view, std::uint32_t&); + template void SettingSave(void*, std::string_view, std::int8_t&); + template void SettingSave(void*, std::string_view, std::int16_t&); + template void SettingSave(void*, std::string_view, std::int32_t&); + template void SettingSave(void*, std::string_view, std::string&); } -} -template <> -void REX::TOML::detail::SettingSaveImpl( - [[maybe_unused]] void* a_file, - [[maybe_unused]] std::uint16_t& a_value, - [[maybe_unused]] std::string_view& a_path) -{ - // auto file = static_cast(a_file); - // file->insert_or_assign(a_path, a_value); -} + void SettingStore::Load() + { + if (auto result = toml::parse_file(m_fileBase)) { + for (auto& setting : m_settings) + setting->Load(&result.table(), true); + } -template <> -void REX::TOML::detail::SettingLoadImpl( - void* a_file, - std::uint32_t& a_value, - std::uint32_t& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - if (auto node = file->at_path(a_path)) { - a_value = node.value_or(a_useDefault ? a_valueDefault : a_value); + if (auto result = toml::parse_file(m_fileUser)) { + for (auto& setting : m_settings) + setting->Load(&result.table(), false); + } } -} -template <> -void REX::TOML::detail::SettingSaveImpl( - [[maybe_unused]] void* a_file, - [[maybe_unused]] std::uint32_t& a_value, - [[maybe_unused]] std::string_view& a_path) -{ - // auto file = static_cast(a_file); - // file->insert_or_assign(a_path, a_value); -} - -template <> -void REX::TOML::detail::SettingLoadImpl( - void* a_file, - std::string& a_value, - std::string& a_valueDefault, - bool a_useDefault, - std::string_view& a_path) -{ - auto file = static_cast(a_file); - if (auto node = file->at_path(a_path)) { - a_value = node.value_or(a_useDefault ? a_valueDefault : a_value); + void SettingStore::Save() + { + // TODO } } - -template <> -void REX::TOML::detail::SettingSaveImpl( - [[maybe_unused]] void* a_file, - [[maybe_unused]] std::string& a_value, - [[maybe_unused]] std::string_view& a_path) -{ - // auto file = static_cast(a_file); - // file->insert_or_assign(a_path, a_value); -} #endif diff --git a/xmake.lua b/xmake.lua index ca4e1720e..403bf8d4e 100644 --- a/xmake.lua +++ b/xmake.lua @@ -54,7 +54,7 @@ if has_config("skse_xbyak") then end if has_config("rex_ini") then - add_requires("simpleini", { configs = { convert = "none" } }) + add_requires("inifile-cpp") end if has_config("rex_json") then @@ -81,7 +81,7 @@ target("commonlibsse", function() end if has_config("rex_ini") then - add_packages("simpleini", { public = true }) + add_packages("inifile-cpp", { public = true }) end if has_config("rex_json") then