// Copyright 2016 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include #include #include "Common/Config/ConfigInfo.h" #include "Common/Config/Enums.h" #include "Common/Config/Layer.h" namespace Config { struct ConfigChangedCallbackID { size_t id = -1; bool operator==(const ConfigChangedCallbackID&) const = default; bool operator!=(const ConfigChangedCallbackID&) const = default; }; using ConfigChangedCallback = std::function; // Layer management void AddLayer(std::unique_ptr loader); std::shared_ptr GetLayer(LayerType layer); void RemoveLayer(LayerType layer); // Returns an ID that can be passed to RemoveConfigChangedCallback(). // The callback may be called from any thread. ConfigChangedCallbackID AddConfigChangedCallback(ConfigChangedCallback func); void RemoveConfigChangedCallback(ConfigChangedCallbackID callback_id); void OnConfigChanged(); // Returns the number of times the config has changed in the current execution of the program u64 GetConfigVersion(); // Explicit load and save of layers void Load(); void Save(); void Init(); void Shutdown(); void ClearCurrentRunLayer(); const std::string& GetSystemName(System system); std::optional GetSystemFromName(const std::string& system); const std::string& GetLayerName(LayerType layer); LayerType GetActiveLayerForConfig(const Location&); std::optional GetAsString(const Location&); template T Get(LayerType layer, const Info& info) { if (layer == LayerType::Meta) return Get(info); return GetLayer(layer)->Get(info); } template T Get(const Info& info) { CachedValue cached = info.GetCachedValue(); const u64 config_version = GetConfigVersion(); if (cached.config_version < config_version) { cached.value = GetUncached(info); cached.config_version = config_version; info.SetCachedValue(cached); } return cached.value; } template T GetUncached(const Info& info) { const std::optional str = GetAsString(info.GetLocation()); if (!str) return info.GetDefaultValue(); return detail::TryParse(*str).value_or(info.GetDefaultValue()); } template T GetBase(const Info& info) { return Get(LayerType::Base, info); } template LayerType GetActiveLayerForConfig(const Info& info) { return GetActiveLayerForConfig(info.GetLocation()); } template void Set(LayerType layer, const Info& info, const std::common_type_t& value) { if (GetLayer(layer)->Set(info, value)) OnConfigChanged(); } template void SetBase(const Info& info, const std::common_type_t& value) { Set(LayerType::Base, info, value); } template void SetCurrent(const Info& info, const std::common_type_t& value) { Set(LayerType::CurrentRun, info, value); } template void SetBaseOrCurrent(const Info& info, const std::common_type_t& value) { if (GetActiveLayerForConfig(info) == LayerType::Base) Set(LayerType::Base, info, value); else Set(LayerType::CurrentRun, info, value); } template void DeleteKey(LayerType layer, const Info& info) { if (GetLayer(layer)->DeleteKey(info.GetLocation())) OnConfigChanged(); } // Used to defer OnConfigChanged until after the completion of many config changes. class ConfigChangeCallbackGuard { public: ConfigChangeCallbackGuard(); ~ConfigChangeCallbackGuard(); ConfigChangeCallbackGuard(const ConfigChangeCallbackGuard&) = delete; ConfigChangeCallbackGuard& operator=(const ConfigChangeCallbackGuard&) = delete; }; } // namespace Config