From e7c48948338ed1e4d5aee1d3fcb36238120edce4 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Mon, 22 Aug 2022 23:21:39 +1000 Subject: [PATCH] Common: Add MemorySettingsInterface --- common/CMakeLists.txt | 3 + common/HeterogeneousContainers.h | 78 ++++++++ common/MemorySettingsInterface.cpp | 290 +++++++++++++++++++++++++++++ common/MemorySettingsInterface.h | 68 +++++++ common/common.vcxproj | 3 + common/common.vcxproj.filters | 9 + 6 files changed, 451 insertions(+) create mode 100644 common/HeterogeneousContainers.h create mode 100644 common/MemorySettingsInterface.cpp create mode 100644 common/MemorySettingsInterface.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 9c6450a751..4765931909 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -21,6 +21,7 @@ target_sources(common PRIVATE FileSystem.cpp Image.cpp HTTPDownloader.cpp + MemorySettingsInterface.cpp Misc.cpp MD5Digest.cpp PrecompiledHeader.cpp @@ -72,10 +73,12 @@ target_sources(common PRIVATE FileSystem.h General.h HashCombine.h + HeterogeneousContainers.h Image.h LRUCache.h HTTPDownloader.h MemcpyFast.h + MemorySettingsInterface.h MemsetFast.inl MD5Digest.h MRCHelpers.h diff --git a/common/HeterogeneousContainers.h b/common/HeterogeneousContainers.h new file mode 100644 index 0000000000..f19ec80360 --- /dev/null +++ b/common/HeterogeneousContainers.h @@ -0,0 +1,78 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +/** + * Provides a map template which doesn't require heap allocations for lookups. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace detail +{ + struct transparent_string_hash + { + using is_transparent = void; + + std::size_t operator()(const std::string_view& v) const { return std::hash{}(v); } + std::size_t operator()(const std::string& s) const { return std::hash{}(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 + +template +using UnorderedStringMap = + std::unordered_map; +template +using UnorderedStringMultimap = + std::unordered_multimap; +using UnorderedStringSet = + std::unordered_set; +using UnorderedStringMultiSet = + std::unordered_multiset; + +template +using StringMap = std::map; +template +using StringMultiMap = std::multimap; +using StringSet = std::set; +using StringMultiSet = std::multiset; diff --git a/common/MemorySettingsInterface.cpp b/common/MemorySettingsInterface.cpp new file mode 100644 index 0000000000..8414a49ff5 --- /dev/null +++ b/common/MemorySettingsInterface.cpp @@ -0,0 +1,290 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2022 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "common/MemorySettingsInterface.h" +#include "common/StringUtil.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 parsed = StringUtil::FromChars(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 parsed = StringUtil::FromChars(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 parsed = StringUtil::FromChars(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 parsed = StringUtil::FromChars(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 parsed = StringUtil::FromChars(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 MemorySettingsInterface::GetStringList(const char* section, const char* key) const +{ + std::vector 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& 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); +} diff --git a/common/MemorySettingsInterface.h b/common/MemorySettingsInterface.h new file mode 100644 index 0000000000..c1fc1926c1 --- /dev/null +++ b/common/MemorySettingsInterface.h @@ -0,0 +1,68 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2022 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once +#include "HeterogeneousContainers.h" +#include "SettingsInterface.h" +#include + +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 GetStringList(const char* section, const char* key) const override; + void SetStringList(const char* section, const char* key, const std::vector& 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; + using SectionMap = UnorderedStringMap; + + void SetValue(const char* section, const char* key, std::string value); + + SectionMap m_sections; +}; \ No newline at end of file diff --git a/common/common.vcxproj b/common/common.vcxproj index 418ffbb4d1..1f96255e94 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -79,6 +79,7 @@ + @@ -151,6 +152,7 @@ + @@ -159,6 +161,7 @@ + diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters index c660342c36..8f2bc35dd2 100644 --- a/common/common.vcxproj.filters +++ b/common/common.vcxproj.filters @@ -199,6 +199,9 @@ Source Files + + Source Files + @@ -468,6 +471,12 @@ Header Files + + Header Files + + + Header Files +