Add MemorySettingsInterface

This commit is contained in:
Connor McLaughlin
2022-07-09 14:17:57 +10:00
parent 462eb2c155
commit f6b3652ae6
11 changed files with 395 additions and 213 deletions

View File

@ -30,6 +30,7 @@ add_library(common
gl/texture.h
hash_combine.h
heap_array.h
heterogeneous_containers.h
layered_settings_interface.cpp
layered_settings_interface.h
log.cpp
@ -37,6 +38,8 @@ add_library(common
make_array.h
md5_digest.cpp
md5_digest.h
memory_settings_interface.cpp
memory_settings_interface.h
minizip_helpers.cpp
minizip_helpers.h
path.h

View File

@ -49,6 +49,7 @@
<ClInclude Include="log.h" />
<ClInclude Include="lru_cache.h" />
<ClInclude Include="make_array.h" />
<ClInclude Include="memory_settings_interface.h" />
<ClInclude Include="md5_digest.h" />
<ClInclude Include="path.h" />
<ClInclude Include="pbp_types.h" />
@ -58,6 +59,7 @@
<ClInclude Include="scope_guard.h" />
<ClInclude Include="settings_interface.h" />
<ClInclude Include="string.h" />
<ClInclude Include="heterogeneous_containers.h" />
<ClInclude Include="string_util.h" />
<ClInclude Include="thirdparty\StackWalker.h">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
@ -120,6 +122,7 @@
<ClCompile Include="image.cpp" />
<ClCompile Include="layered_settings_interface.cpp" />
<ClCompile Include="log.cpp" />
<ClCompile Include="memory_settings_interface.cpp" />
<ClCompile Include="md5_digest.cpp" />
<ClCompile Include="minizip_helpers.cpp" />
<ClCompile Include="progress_callback.cpp" />

View File

@ -135,6 +135,8 @@
</ClInclude>
<ClInclude Include="settings_interface.h" />
<ClInclude Include="layered_settings_interface.h" />
<ClInclude Include="heterogeneous_containers.h" />
<ClInclude Include="memory_settings_interface.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="gl\program.cpp">
@ -247,6 +249,7 @@
<Filter>vulkan</Filter>
</ClCompile>
<ClCompile Include="layered_settings_interface.cpp" />
<ClCompile Include="memory_settings_interface.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="bitfield.natvis" />

View File

@ -0,0 +1,97 @@
/**
* Provides a map template which doesn't require heap allocations for lookups.
*/
#pragma once
#include "types.h"
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
namespace detail {
struct transparent_string_hash
{
using is_transparent = void;
std::size_t operator()(const std::string_view& v) const { return std::hash<std::string_view>{}(v); }
std::size_t operator()(const std::string& s) const { return std::hash<std::string>{}(s); }
std::size_t operator()(const char* s) const { return operator()(std::string_view(s)); }
};
struct transparent_string_equal
{
using is_transparent = void;
bool operator()(const std::string& lhs, const std::string_view& rhs) const { return lhs == rhs; }
bool operator()(const std::string& lhs, const std::string& rhs) const { return lhs == rhs; }
bool operator()(const std::string& lhs, const char* rhs) const { return lhs == rhs; }
bool operator()(const std::string_view& lhs, const std::string& rhs) const { return lhs == rhs; }
bool operator()(const char* lhs, const std::string& rhs) const { return lhs == rhs; }
};
struct transparent_string_less
{
using is_transparent = void;
bool operator()(const std::string& lhs, const std::string_view& rhs) const { return lhs < rhs; }
bool operator()(const std::string& lhs, const std::string& rhs) const { return lhs < rhs; }
bool operator()(const std::string& lhs, const char* rhs) const { return lhs < rhs; }
bool operator()(const std::string_view& lhs, const std::string& rhs) const { return lhs < rhs; }
bool operator()(const char* lhs, const std::string& rhs) const { return lhs < rhs; }
};
} // namespace detail
// This requires C++20, so fallback to ugly heap allocations if we don't have it.
#if __cplusplus >= 202002L
template<typename ValueType>
using UnorderedStringMap =
std::unordered_map<std::string, ValueType, detail::transparent_string_hash, detail::transparent_string_equal>;
template<typename ValueType>
using UnorderedStringMultimap =
std::unordered_multimap<std::string, ValueType, detail::transparent_string_hash, detail::transparent_string_equal>;
using UnorderedStringSet =
std::unordered_set<std::string, detail::transparent_string_hash, detail::transparent_string_equal>;
using UnorderedStringMultiSet =
std::unordered_multiset<std::string, detail::transparent_string_hash, detail::transparent_string_equal>;
template<typename KeyType, typename ValueType>
ALWAYS_INLINE typename UnorderedStringMap<ValueType>::const_iterator
UnorderedStringMapFind(const UnorderedStringMap<ValueType>& map, const KeyType& key)
{
return map.find(key);
}
template<typename KeyType, typename ValueType>
ALWAYS_INLINE typename UnorderedStringMap<ValueType>::iterator
UnorderedStringMapFind(UnorderedStringMap<ValueType>& map, const KeyType& key)
{
return map.find(key);
}
#else
template<typename ValueType>
using UnorderedStringMap = std::unordered_map<std::string, ValueType>;
template<typename ValueType>
using UnorderedStringMultimap = std::unordered_multimap<std::string, ValueType>;
using UnorderedStringSet = std::unordered_set<std::string>;
using UnorderedStringMultiSet = std::unordered_multiset<std::string>;
template<typename KeyType, typename ValueType>
ALWAYS_INLINE typename UnorderedStringMap<ValueType>::const_iterator UnorderedStringMapFind(const UnorderedStringMap<ValueType>& map, const KeyType& key)
{
return map.find(std::string(key));
}
template<typename KeyType, typename ValueType>
ALWAYS_INLINE typename UnorderedStringMap<ValueType>::iterator UnorderedStringMapFind(UnorderedStringMap<ValueType>& map, const KeyType& key)
{
return map.find(std::string(key));
}
#endif
template<typename ValueType>
using StringMap = std::map<std::string, ValueType, detail::transparent_string_less>;
template<typename ValueType>
using StringMultiMap = std::multimap<std::string, ValueType, detail::transparent_string_less>;
using StringSet = std::set<std::string, detail::transparent_string_less>;
using StringMultiSet = std::multiset<std::string, detail::transparent_string_less>;

View File

@ -0,0 +1,276 @@
#include "memory_settings_interface.h"
#include "common/assert.h"
#include "common/string_util.h"
MemorySettingsInterface::MemorySettingsInterface() = default;
MemorySettingsInterface::~MemorySettingsInterface() = default;
bool MemorySettingsInterface::Save()
{
return false;
}
void MemorySettingsInterface::Clear()
{
m_sections.clear();
}
bool MemorySettingsInterface::GetIntValue(const char* section, const char* key, s32* value) const
{
const auto sit = m_sections.find(section);
if (sit == m_sections.end())
return false;
const auto iter = sit->second.find(key);
if (iter == sit->second.end())
return false;
std::optional<s32> parsed = StringUtil::FromChars<s32>(iter->second, 10);
if (!parsed.has_value())
return false;
*value = parsed.value();
return true;
}
bool MemorySettingsInterface::GetUIntValue(const char* section, const char* key, u32* value) const
{
const auto sit = m_sections.find(section);
if (sit == m_sections.end())
return false;
const auto iter = sit->second.find(key);
if (iter == sit->second.end())
return false;
std::optional<u32> parsed = StringUtil::FromChars<u32>(iter->second, 10);
if (!parsed.has_value())
return false;
*value = parsed.value();
return true;
}
bool MemorySettingsInterface::GetFloatValue(const char* section, const char* key, float* value) const
{
const auto sit = m_sections.find(section);
if (sit == m_sections.end())
return false;
const auto iter = sit->second.find(key);
if (iter == sit->second.end())
return false;
std::optional<float> parsed = StringUtil::FromChars<float>(iter->second);
if (!parsed.has_value())
return false;
*value = parsed.value();
return true;
}
bool MemorySettingsInterface::GetDoubleValue(const char* section, const char* key, double* value) const
{
const auto sit = m_sections.find(section);
if (sit == m_sections.end())
return false;
const auto iter = sit->second.find(key);
if (iter == sit->second.end())
return false;
std::optional<double> parsed = StringUtil::FromChars<double>(iter->second);
if (!parsed.has_value())
return false;
*value = parsed.value();
return true;
}
bool MemorySettingsInterface::GetBoolValue(const char* section, const char* key, bool* value) const
{
const auto sit = m_sections.find(section);
if (sit == m_sections.end())
return false;
const auto iter = sit->second.find(key);
if (iter == sit->second.end())
return false;
std::optional<bool> parsed = StringUtil::FromChars<bool>(iter->second);
if (!parsed.has_value())
return false;
*value = parsed.value();
return true;
}
bool MemorySettingsInterface::GetStringValue(const char* section, const char* key, std::string* value) const
{
const auto sit = m_sections.find(section);
if (sit == m_sections.end())
return false;
const auto iter = sit->second.find(key);
if (iter == sit->second.end())
return false;
*value = iter->second;
return true;
}
void MemorySettingsInterface::SetIntValue(const char* section, const char* key, s32 value)
{
SetValue(section, key, std::to_string(value));
}
void MemorySettingsInterface::SetUIntValue(const char* section, const char* key, u32 value)
{
SetValue(section, key, std::to_string(value));
}
void MemorySettingsInterface::SetFloatValue(const char* section, const char* key, float value)
{
SetValue(section, key, std::to_string(value));
}
void MemorySettingsInterface::SetDoubleValue(const char* section, const char* key, double value)
{
SetValue(section, key, std::to_string(value));
}
void MemorySettingsInterface::SetBoolValue(const char* section, const char* key, bool value)
{
SetValue(section, key, std::to_string(value));
}
void MemorySettingsInterface::SetStringValue(const char* section, const char* key, const char* value)
{
SetValue(section, key, value);
}
void MemorySettingsInterface::SetValue(const char* section, const char* key, std::string value)
{
auto sit = m_sections.find(section);
if (sit == m_sections.end())
sit = m_sections.emplace(std::make_pair(std::string(section), KeyMap())).first;
const auto range = sit->second.equal_range(key);
if (range.first == sit->second.end())
{
sit->second.emplace(std::string(key), std::move(value));
return;
}
auto iter = range.first;
iter->second = std::move(value);
++iter;
// remove other values
while (iter != range.second)
{
auto remove = iter++;
sit->second.erase(remove);
}
}
std::vector<std::string> MemorySettingsInterface::GetStringList(const char* section, const char* key) const
{
std::vector<std::string> ret;
const auto sit = m_sections.find(section);
if (sit != m_sections.end())
{
const auto range = sit->second.equal_range(key);
for (auto iter = range.first; iter != range.second; ++iter)
ret.emplace_back(iter->second);
}
return ret;
}
void MemorySettingsInterface::SetStringList(const char* section, const char* key, const std::vector<std::string>& items)
{
auto sit = m_sections.find(section);
if (sit == m_sections.end())
sit = m_sections.emplace(std::make_pair(std::string(section), KeyMap())).first;
const auto range = sit->second.equal_range(key);
for (auto iter = range.first; iter != range.second;)
sit->second.erase(iter++);
std::string_view keysv(key);
for (const std::string& value : items)
sit->second.emplace(keysv, value);
}
bool MemorySettingsInterface::RemoveFromStringList(const char* section, const char* key, const char* item)
{
auto sit = m_sections.find(section);
if (sit == m_sections.end())
sit = m_sections.emplace(std::make_pair(std::string(section), KeyMap())).first;
const auto range = sit->second.equal_range(key);
bool result = false;
for (auto iter = range.first; iter != range.second;)
{
if (iter->second == item)
{
sit->second.erase(iter++);
result = true;
}
else
{
++iter;
}
}
return result;
}
bool MemorySettingsInterface::AddToStringList(const char* section, const char* key, const char* item)
{
auto sit = m_sections.find(section);
if (sit == m_sections.end())
sit = m_sections.emplace(std::make_pair(std::string(section), KeyMap())).first;
const auto range = sit->second.equal_range(key);
for (auto iter = range.first; iter != range.second; ++iter)
{
if (iter->second == item)
return false;
}
sit->second.emplace(std::string(key), std::string(item));
return true;
}
bool MemorySettingsInterface::ContainsValue(const char* section, const char* key) const
{
const auto sit = m_sections.find(section);
if (sit == m_sections.end())
return false;
return (sit->second.find(key) != sit->second.end());
}
void MemorySettingsInterface::DeleteValue(const char* section, const char* key)
{
auto sit = m_sections.find(section);
if (sit == m_sections.end())
return;
const auto range = sit->second.equal_range(key);
for (auto iter = range.first; iter != range.second;)
sit->second.erase(iter++);
}
void MemorySettingsInterface::ClearSection(const char* section)
{
auto sit = m_sections.find(section);
if (sit == m_sections.end())
return;
m_sections.erase(sit);
}

View File

@ -0,0 +1,53 @@
#pragma once
#include "heterogeneous_containers.h"
#include "settings_interface.h"
#include <string>
class MemorySettingsInterface final : public SettingsInterface
{
public:
MemorySettingsInterface();
~MemorySettingsInterface();
bool Save() override;
void Clear() override;
bool GetIntValue(const char* section, const char* key, s32* value) const override;
bool GetUIntValue(const char* section, const char* key, u32* value) const override;
bool GetFloatValue(const char* section, const char* key, float* value) const override;
bool GetDoubleValue(const char* section, const char* key, double* value) const override;
bool GetBoolValue(const char* section, const char* key, bool* value) const override;
bool GetStringValue(const char* section, const char* key, std::string* value) const override;
void SetIntValue(const char* section, const char* key, s32 value) override;
void SetUIntValue(const char* section, const char* key, u32 value) override;
void SetFloatValue(const char* section, const char* key, float value) override;
void SetDoubleValue(const char* section, const char* key, double value) override;
void SetBoolValue(const char* section, const char* key, bool value) override;
void SetStringValue(const char* section, const char* key, const char* value) override;
bool ContainsValue(const char* section, const char* key) const override;
void DeleteValue(const char* section, const char* key) override;
void ClearSection(const char* section) override;
std::vector<std::string> GetStringList(const char* section, const char* key) const override;
void SetStringList(const char* section, const char* key, const std::vector<std::string>& items) override;
bool RemoveFromStringList(const char* section, const char* key, const char* item) override;
bool AddToStringList(const char* section, const char* key, const char* item) override;
// default parameter overloads
using SettingsInterface::GetBoolValue;
using SettingsInterface::GetDoubleValue;
using SettingsInterface::GetFloatValue;
using SettingsInterface::GetIntValue;
using SettingsInterface::GetStringValue;
using SettingsInterface::GetUIntValue;
private:
using KeyMap = UnorderedStringMultimap<std::string>;
using SectionMap = UnorderedStringMap<KeyMap>;
void SetValue(const char* section, const char* key, std::string value);
SectionMap m_sections;
};