mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 22:29:39 -06:00
Config: Flatten structures
Originally, Layer contained a std::map of Sections, which containted a std::map containing the (key, value) pairs. Here we flattern this structure so that only one std::map is required, reducing the number of indirections required and vastly simplifying the code.
This commit is contained in:
@ -133,7 +133,7 @@ LayerType GetActiveLayerForConfig(const ConfigLocation& config)
|
||||
if (!LayerExists(layer))
|
||||
continue;
|
||||
|
||||
if (GetLayer(layer)->Exists(config.system, config.section, config.key))
|
||||
if (GetLayer(layer)->Exists(config))
|
||||
return layer;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "Common/Config/ConfigInfo.h"
|
||||
#include "Common/Config/Enums.h"
|
||||
#include "Common/Config/Layer.h"
|
||||
#include "Common/Config/Section.h"
|
||||
|
||||
namespace Config
|
||||
{
|
||||
|
@ -8,10 +8,47 @@
|
||||
|
||||
#include "Common/Config/Config.h"
|
||||
#include "Common/Config/Layer.h"
|
||||
#include "Common/Config/Section.h"
|
||||
|
||||
namespace Config
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
std::string ValueToString(u16 value)
|
||||
{
|
||||
return StringFromFormat("0x%04x", value);
|
||||
}
|
||||
|
||||
std::string ValueToString(u32 value)
|
||||
{
|
||||
return StringFromFormat("0x%08x", value);
|
||||
}
|
||||
|
||||
std::string ValueToString(float value)
|
||||
{
|
||||
return StringFromFormat("%#.9g", value);
|
||||
}
|
||||
|
||||
std::string ValueToString(double value)
|
||||
{
|
||||
return StringFromFormat("%#.17g", value);
|
||||
}
|
||||
|
||||
std::string ValueToString(int value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
|
||||
std::string ValueToString(bool value)
|
||||
{
|
||||
return StringFromBool(value);
|
||||
}
|
||||
|
||||
std::string ValueToString(const std::string& value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
ConfigLayerLoader::ConfigLayerLoader(LayerType layer) : m_layer(layer)
|
||||
{
|
||||
}
|
||||
@ -38,56 +75,44 @@ Layer::~Layer()
|
||||
Save();
|
||||
}
|
||||
|
||||
bool Layer::Exists(System system, const std::string& section_name, const std::string& key)
|
||||
bool Layer::Exists(const ConfigLocation& location) const
|
||||
{
|
||||
Section* section = GetSection(system, section_name);
|
||||
if (!section)
|
||||
return false;
|
||||
return section->Exists(key);
|
||||
const auto iter = m_map.find(location);
|
||||
return iter != m_map.end() && iter->second.has_value();
|
||||
}
|
||||
|
||||
bool Layer::DeleteKey(System system, const std::string& section_name, const std::string& key)
|
||||
bool Layer::DeleteKey(const ConfigLocation& location)
|
||||
{
|
||||
Section* section = GetSection(system, section_name);
|
||||
if (!section)
|
||||
return false;
|
||||
return section->Delete(key);
|
||||
m_is_dirty = true;
|
||||
bool had_value = m_map[location].has_value();
|
||||
m_map[location].reset();
|
||||
return had_value;
|
||||
}
|
||||
|
||||
Section* Layer::GetSection(System system, const std::string& section_name)
|
||||
void Layer::DeleteAllKeys()
|
||||
{
|
||||
for (auto& section : m_sections[system])
|
||||
if (!strcasecmp(section->m_name.c_str(), section_name.c_str()))
|
||||
return section.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Section* Layer::GetOrCreateSection(System system, const std::string& section_name)
|
||||
{
|
||||
Section* section = GetSection(system, section_name);
|
||||
if (!section)
|
||||
m_is_dirty = true;
|
||||
for (auto& pair : m_map)
|
||||
{
|
||||
m_sections[system].emplace_back(std::make_unique<Section>(m_layer, system, section_name));
|
||||
section = m_sections[system].back().get();
|
||||
pair.second.reset();
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
void Layer::Load()
|
||||
{
|
||||
if (m_loader)
|
||||
m_loader->Load(this);
|
||||
ClearDirty();
|
||||
m_is_dirty = false;
|
||||
InvokeConfigChangedCallbacks();
|
||||
}
|
||||
|
||||
void Layer::Save()
|
||||
{
|
||||
if (!m_loader || !IsDirty())
|
||||
if (!m_loader || !m_is_dirty)
|
||||
return;
|
||||
|
||||
m_loader->Save(this);
|
||||
ClearDirty();
|
||||
m_is_dirty = false;
|
||||
InvokeConfigChangedCallbacks();
|
||||
}
|
||||
|
||||
@ -98,22 +123,6 @@ LayerType Layer::GetLayer() const
|
||||
|
||||
const LayerMap& Layer::GetLayerMap() const
|
||||
{
|
||||
return m_sections;
|
||||
}
|
||||
|
||||
bool Layer::IsDirty() const
|
||||
{
|
||||
return std::any_of(m_sections.begin(), m_sections.end(), [](const auto& system) {
|
||||
return std::any_of(system.second.begin(), system.second.end(),
|
||||
[](const auto& section) { return section->IsDirty(); });
|
||||
});
|
||||
}
|
||||
|
||||
void Layer::ClearDirty()
|
||||
{
|
||||
std::for_each(m_sections.begin(), m_sections.end(), [](auto& system) {
|
||||
std::for_each(system.second.begin(), system.second.end(),
|
||||
[](auto& section) { section->ClearDirty(); });
|
||||
});
|
||||
return m_map;
|
||||
}
|
||||
}
|
||||
|
@ -6,18 +6,47 @@
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/Config/ConfigInfo.h"
|
||||
#include "Common/Config/Enums.h"
|
||||
#include "Common/Config/Section.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
namespace Config
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
std::string ValueToString(u16 value);
|
||||
std::string ValueToString(u32 value);
|
||||
std::string ValueToString(float value);
|
||||
std::string ValueToString(double value);
|
||||
std::string ValueToString(int value);
|
||||
std::string ValueToString(bool value);
|
||||
std::string ValueToString(const std::string& value);
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> TryParse(const std::string& str_value)
|
||||
{
|
||||
T value;
|
||||
if (!::TryParse(str_value, &value))
|
||||
return std::nullopt;
|
||||
return value;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::optional<std::string> TryParse(const std::string& str_value)
|
||||
{
|
||||
return str_value;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct ConfigInfo;
|
||||
|
||||
using LayerMap = std::map<System, std::vector<std::unique_ptr<Section>>>;
|
||||
class Layer;
|
||||
using LayerMap = std::map<ConfigLocation, std::optional<std::string>>;
|
||||
|
||||
class ConfigLayerLoader
|
||||
{
|
||||
@ -41,32 +70,40 @@ public:
|
||||
virtual ~Layer();
|
||||
|
||||
// Convenience functions
|
||||
bool Exists(System system, const std::string& section_name, const std::string& key);
|
||||
bool DeleteKey(System system, const std::string& section_name, const std::string& key);
|
||||
template <typename T>
|
||||
bool GetIfExists(System system, const std::string& section_name, const std::string& key, T* value)
|
||||
{
|
||||
if (Exists(system, section_name, key))
|
||||
return GetOrCreateSection(system, section_name)->Get(key, value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Section* GetSection(System system, const std::string& section_name);
|
||||
virtual Section* GetOrCreateSection(System system, const std::string& section_name);
|
||||
bool Exists(const ConfigLocation& location) const;
|
||||
bool DeleteKey(const ConfigLocation& location);
|
||||
void DeleteAllKeys();
|
||||
|
||||
template <typename T>
|
||||
T Get(const ConfigInfo<T>& config_info)
|
||||
{
|
||||
return GetOrCreateSection(config_info.location.system, config_info.location.section)
|
||||
->template Get<T>(config_info.location.key, config_info.default_value);
|
||||
return Get<T>(config_info.location).value_or(config_info.default_value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> Get(const ConfigLocation& location)
|
||||
{
|
||||
const std::optional<std::string>& str_value = m_map[location];
|
||||
if (!str_value)
|
||||
return std::nullopt;
|
||||
return detail::TryParse<T>(*str_value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Set(const ConfigInfo<T>& config_info, const T& value)
|
||||
{
|
||||
GetOrCreateSection(config_info.location.system, config_info.location.section)
|
||||
->Set(config_info.location.key, value);
|
||||
Set<T>(config_info.location, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Set(const ConfigLocation& location, const T& value)
|
||||
{
|
||||
const std::string new_value = detail::ValueToString(value);
|
||||
std::optional<std::string>& current_value = m_map[location];
|
||||
if (current_value == new_value)
|
||||
return;
|
||||
m_is_dirty = true;
|
||||
current_value = new_value;
|
||||
}
|
||||
|
||||
// Explicit load and save of layers
|
||||
@ -77,11 +114,9 @@ public:
|
||||
const LayerMap& GetLayerMap() const;
|
||||
|
||||
protected:
|
||||
bool IsDirty() const;
|
||||
void ClearDirty();
|
||||
|
||||
LayerMap m_sections;
|
||||
bool m_is_dirty = false;
|
||||
LayerMap m_map;
|
||||
const LayerType m_layer;
|
||||
std::unique_ptr<ConfigLayerLoader> m_loader;
|
||||
};
|
||||
} // namespace Config
|
||||
}
|
||||
|
@ -1,249 +0,0 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/Config/Config.h"
|
||||
#include "Common/Config/Layer.h"
|
||||
#include "Common/Config/Section.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
namespace Config
|
||||
{
|
||||
const std::string& Section::NULL_STRING = "";
|
||||
|
||||
Section::Section(LayerType layer, System system, const std::string& name)
|
||||
: m_layer(layer), m_system(system), m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
bool Section::Exists(const std::string& key) const
|
||||
{
|
||||
return m_values.find(key) != m_values.end();
|
||||
}
|
||||
|
||||
bool Section::Delete(const std::string& key)
|
||||
{
|
||||
auto it = m_values.find(key);
|
||||
if (it == m_values.end())
|
||||
return false;
|
||||
|
||||
m_values.erase(it);
|
||||
|
||||
m_deleted_keys.push_back(key);
|
||||
m_dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Section::Set(const std::string& key, const std::string& value)
|
||||
{
|
||||
auto it = m_values.find(key);
|
||||
if (it != m_values.end() && it->second != value)
|
||||
{
|
||||
it->second = value;
|
||||
m_dirty = true;
|
||||
}
|
||||
else if (it == m_values.end())
|
||||
{
|
||||
m_values[key] = value;
|
||||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Section::Set(const std::string& key, u16 newValue)
|
||||
{
|
||||
Section::Set(key, StringFromFormat("0x%04x", newValue));
|
||||
}
|
||||
|
||||
void Section::Set(const std::string& key, u32 newValue)
|
||||
{
|
||||
Section::Set(key, StringFromFormat("0x%08x", newValue));
|
||||
}
|
||||
|
||||
void Section::Set(const std::string& key, float newValue)
|
||||
{
|
||||
Section::Set(key, StringFromFormat("%#.9g", newValue));
|
||||
}
|
||||
|
||||
void Section::Set(const std::string& key, double newValue)
|
||||
{
|
||||
Section::Set(key, StringFromFormat("%#.17g", newValue));
|
||||
}
|
||||
|
||||
void Section::Set(const std::string& key, int newValue)
|
||||
{
|
||||
Section::Set(key, std::to_string(newValue));
|
||||
}
|
||||
|
||||
void Section::Set(const std::string& key, bool newValue)
|
||||
{
|
||||
Section::Set(key, StringFromBool(newValue));
|
||||
}
|
||||
|
||||
void Section::Set(const std::string& key, const std::string& newValue,
|
||||
const std::string& defaultValue)
|
||||
{
|
||||
if (newValue != defaultValue)
|
||||
Set(key, newValue);
|
||||
else
|
||||
Delete(key);
|
||||
}
|
||||
|
||||
void Section::SetLines(const std::vector<std::string>& lines)
|
||||
{
|
||||
m_lines = lines;
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
bool Section::Get(const std::string& key, std::string* value,
|
||||
const std::string& default_value) const
|
||||
{
|
||||
const auto& it = m_values.find(key);
|
||||
if (it != m_values.end())
|
||||
{
|
||||
*value = it->second;
|
||||
return true;
|
||||
}
|
||||
else if (&default_value != &NULL_STRING)
|
||||
{
|
||||
*value = default_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const std::string& key, int* value, int defaultValue) const
|
||||
{
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp);
|
||||
|
||||
if (retval && TryParse(temp, value))
|
||||
return true;
|
||||
|
||||
*value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const std::string& key, u16* value, u16 defaultValue) const
|
||||
{
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp);
|
||||
|
||||
if (retval && TryParse(temp, value))
|
||||
return true;
|
||||
|
||||
*value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const std::string& key, u32* value, u32 defaultValue) const
|
||||
{
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp);
|
||||
|
||||
if (retval && TryParse(temp, value))
|
||||
return true;
|
||||
|
||||
*value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const std::string& key, bool* value, bool defaultValue) const
|
||||
{
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp);
|
||||
|
||||
if (retval && TryParse(temp, value))
|
||||
return true;
|
||||
|
||||
*value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const std::string& key, float* value, float defaultValue) const
|
||||
{
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp);
|
||||
|
||||
if (retval && TryParse(temp, value))
|
||||
return true;
|
||||
|
||||
*value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Section::Get(const std::string& key, double* value, double defaultValue) const
|
||||
{
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp);
|
||||
|
||||
if (retval && TryParse(temp, value))
|
||||
return true;
|
||||
|
||||
*value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return a list of all lines in a section
|
||||
bool Section::GetLines(std::vector<std::string>* lines, const bool remove_comments) const
|
||||
{
|
||||
lines->clear();
|
||||
|
||||
for (std::string line : m_lines)
|
||||
{
|
||||
line = StripSpaces(line);
|
||||
|
||||
if (remove_comments)
|
||||
{
|
||||
size_t commentPos = line.find('#');
|
||||
if (commentPos == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (commentPos != std::string::npos)
|
||||
{
|
||||
line = StripSpaces(line.substr(0, commentPos));
|
||||
}
|
||||
}
|
||||
|
||||
lines->push_back(line);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Section::HasLines() const
|
||||
{
|
||||
return !m_lines.empty();
|
||||
}
|
||||
|
||||
const std::string& Section::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const SectionValueMap& Section::GetValues() const
|
||||
{
|
||||
return m_values;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& Section::GetDeletedKeys() const
|
||||
{
|
||||
return m_deleted_keys;
|
||||
}
|
||||
|
||||
bool Section::IsDirty() const
|
||||
{
|
||||
return m_dirty;
|
||||
}
|
||||
void Section::ClearDirty()
|
||||
{
|
||||
m_dirty = false;
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// XXX: Purely for case insensitive compare
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Config/Enums.h"
|
||||
#include "Common/IniFile.h"
|
||||
|
||||
namespace Config
|
||||
{
|
||||
class Layer;
|
||||
class ConfigLayerLoader;
|
||||
|
||||
using SectionValueMap = std::map<std::string, std::string, CaseInsensitiveStringCompare>;
|
||||
|
||||
class Section
|
||||
{
|
||||
friend Layer;
|
||||
friend ConfigLayerLoader;
|
||||
|
||||
public:
|
||||
Section(LayerType layer, System system, const std::string& name);
|
||||
virtual ~Section() = default;
|
||||
|
||||
virtual bool Exists(const std::string& key) const;
|
||||
bool Delete(const std::string& key);
|
||||
|
||||
// Setters
|
||||
virtual void Set(const std::string& key, const std::string& value);
|
||||
|
||||
void Set(const std::string& key, u16 newValue);
|
||||
void Set(const std::string& key, u32 newValue);
|
||||
void Set(const std::string& key, float newValue);
|
||||
void Set(const std::string& key, double newValue);
|
||||
void Set(const std::string& key, int newValue);
|
||||
void Set(const std::string& key, bool newValue);
|
||||
|
||||
// Setters with default values
|
||||
void Set(const std::string& key, const std::string& newValue, const std::string& defaultValue);
|
||||
template <typename T>
|
||||
void Set(const std::string& key, T newValue, const T defaultValue)
|
||||
{
|
||||
if (newValue != defaultValue)
|
||||
Set(key, newValue);
|
||||
else
|
||||
Delete(key);
|
||||
}
|
||||
|
||||
// Getters
|
||||
virtual bool Get(const std::string& key, std::string* value,
|
||||
const std::string& default_value = NULL_STRING) const;
|
||||
|
||||
bool Get(const std::string& key, int* value, int defaultValue = 0) const;
|
||||
bool Get(const std::string& key, u16* value, u16 defaultValue = 0) const;
|
||||
bool Get(const std::string& key, u32* value, u32 defaultValue = 0) const;
|
||||
bool Get(const std::string& key, bool* value, bool defaultValue = false) const;
|
||||
bool Get(const std::string& key, float* value, float defaultValue = 0.0f) const;
|
||||
bool Get(const std::string& key, double* value, double defaultValue = 0.0) const;
|
||||
|
||||
template <typename T>
|
||||
T Get(const std::string& key, const T& default_value) const
|
||||
{
|
||||
T value;
|
||||
Get(key, &value, default_value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Section chunk
|
||||
void SetLines(const std::vector<std::string>& lines);
|
||||
// XXX: Add to recursive layer
|
||||
virtual bool GetLines(std::vector<std::string>* lines, const bool remove_comments = true) const;
|
||||
virtual bool HasLines() const;
|
||||
const std::string& GetName() const;
|
||||
const SectionValueMap& GetValues() const;
|
||||
const std::vector<std::string>& GetDeletedKeys() const;
|
||||
bool IsDirty() const;
|
||||
void ClearDirty();
|
||||
|
||||
protected:
|
||||
bool m_dirty = false;
|
||||
|
||||
LayerType m_layer;
|
||||
System m_system;
|
||||
const std::string m_name;
|
||||
static const std::string& NULL_STRING;
|
||||
|
||||
SectionValueMap m_values;
|
||||
std::vector<std::string> m_deleted_keys;
|
||||
|
||||
std::vector<std::string> m_lines;
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user