From c5592921831e6f2d3d01b3c27b7dd76350b07b20 Mon Sep 17 00:00:00 2001 From: Zero Fanker Date: Sun, 31 Mar 2024 19:57:33 -0400 Subject: [PATCH] refactored ini management, fixing performance issue and logic error from very low level . --- MissionEditor/IniFile.cpp | 169 ++++++-------------------------------- MissionEditor/IniFile.h | 164 +++++++++++++++++++++++++++++------- MissionEditor/IniHelper.h | 31 +++++++ 3 files changed, 190 insertions(+), 174 deletions(-) create mode 100644 MissionEditor/IniHelper.h diff --git a/MissionEditor/IniFile.cpp b/MissionEditor/IniFile.cpp index 63c7a16..36a9651 100644 --- a/MissionEditor/IniFile.cpp +++ b/MissionEditor/IniFile.cpp @@ -38,6 +38,9 @@ static char THIS_FILE[] = __FILE__; using namespace std; +const CIniFileSection CIniFile::EmptySection; +const CString CIniFileSection::EmptyValue; + bool SortDummy::operator()(const CString& x, const CString& y) const { // the length is more important than spelling (numbers!!!)... @@ -95,14 +98,12 @@ void CIniFile::Clear() CIniFileSection::CIniFileSection() { - values.clear(); - value_orig_pos.clear(); }; CIniFileSection::~CIniFileSection() { - values.clear(); - value_orig_pos.clear(); + value_pos.clear(); + value_pairs.clear(); }; WORD CIniFile::InsertFile(const CString& filename, const char* Section, BOOL bNoSpaces) @@ -158,7 +159,7 @@ WORD CIniFile::InsertFile(const std::string& filename, const char* Section, BOOL CString name = cLine.substr(0, equals).c_str(); CString value = cLine.substr(equals + 1, cLine.size() - equals - 1).c_str(); - int cuValueIndex = sections[cSec].values.size(); + int cuValueIndex = sections[cSec].Size(); if (bNoSpaces) { @@ -166,8 +167,7 @@ WORD CIniFile::InsertFile(const std::string& filename, const char* Section, BOOL value.Trim(); } - sections[cSec].values[name] = value; - sections[cSec].value_orig_pos[name] = cuValueIndex; + sections[cSec].Assign(name, value); } } @@ -180,7 +180,7 @@ WORD CIniFile::InsertFile(const std::string& filename, const char* Section, BOOL return 0; } -const CIniFileSection* CIniFile::GetSection(std::size_t index) const +const CIniFileSection* CIniFile::TryGetSection(std::size_t index) const { if (index > sections.size() - 1) return NULL; @@ -192,7 +192,7 @@ const CIniFileSection* CIniFile::GetSection(std::size_t index) const return &i->second; } -CIniFileSection* CIniFile::GetSection(std::size_t index) +CIniFileSection* CIniFile::TryGetSection(std::size_t index) { if (index > sections.size() - 1) return NULL; @@ -204,59 +204,6 @@ CIniFileSection* CIniFile::GetSection(std::size_t index) return &i->second; } -const CIniFileSection* CIniFile::GetSection(const CString& section) const -{ - auto it = sections.find(section); - if (it == sections.end()) - return nullptr; - return &it->second; -} - -CIniFileSection* CIniFile::GetSection(const CString& section) -{ - auto it = sections.find(section); - if (it == sections.end()) - return nullptr; - return &it->second; -} - -const CString* CIniFileSection::GetValue(std::size_t index) const noexcept -{ - if (index > values.size() - 1) - return NULL; - - auto i = values.begin(); - for (auto e = 0;e < index;e++) - i++; - - return &i->second; -} - -CString* CIniFileSection::GetValue(std::size_t index) noexcept -{ - if (index > values.size() - 1) - return NULL; - - auto i = values.begin(); - for (auto e = 0; e < index; e++) { - if (i == values.end()) { - break; - } - i++; - } - if (i == values.end()) { - return nullptr; - } - - return &i->second; -} - -CString CIniFileSection::GetValueByName(const CString& valueName, const CString& defaultValue) const -{ - auto it = values.find(valueName); - return (it == values.end()) ? defaultValue : it->second; -} - const CString* CIniFile::GetSectionName(std::size_t index) const noexcept { if (index > sections.size() - 1) @@ -274,19 +221,6 @@ CString& CIniFileSection::AccessValueByName(const CString& valueName) return values[valueName]; } -const CString* CIniFileSection::GetValueName(std::size_t index) const noexcept -{ - if (index > values.size() - 1) - return NULL; - - auto i = values.begin(); - for (auto e = 0; e < index; ++e) - i++; - - - return &(i->first); -} - BOOL CIniFile::SaveFile(const CString& filename) const { return SaveFile(std::string(filename.GetString())); @@ -298,14 +232,10 @@ BOOL CIniFile::SaveFile(const std::string& Filename) const file.open(Filename, ios::out | ios::trunc); - int i; - for (i = 0;i < sections.size();i++) - { - file << "[" << (LPCTSTR)*GetSectionName(i) << "]" << endl; - int e; - for (e = 0;e < GetSection(i)->values.size();e++) - { - file << (LPCTSTR) * (GetSection(i)->GetValueName(e)) << "=" << (LPCTSTR)*GetSection(i)->GetValue(e) << endl; + for (auto const& sec : sections) { + file << "[" << sec.first << "]" << endl; + for (auto const& pair : sec.second) { + file << pair.first << "=" << pair.second << endl; } file << endl; } @@ -318,81 +248,28 @@ BOOL CIniFile::SaveFile(const std::string& Filename) const int CIniFileSection::FindValue(CString sval) const noexcept { - int i; - auto it = values.cbegin(); - for (i = 0;i < values.size();i++) - { - if (sval == it->second) - return i; - it++; + for (auto idx = 0; + idx < this->value_pairs.size(); + ++idx) { + if (this->value_pairs[idx].second == sval) { + return idx; + } } return -1; } int CIniFileSection::FindName(CString sval) const noexcept { - int i; - auto it = values.cbegin(); - for (i = 0;i < values.size();i++) - { - if (sval == it->first) - return i; - it++; + auto const it = this->value_pos.find(sval); + if (it != this->value_pos.end()) { + return it->second; } return -1; } -void CIniFile::DeleteLeadingSpaces(BOOL bValueNames, BOOL bValues) -{ - int i; - for (i = 0;i < sections.size();i++) - { - CIniFileSection& sec = *GetSection(i); - int e; - for (e = 0;e < sec.values.size();e++) - { - if (bValues) sec.GetValue(e)->TrimLeft(); - if (bValueNames) - { - CString value = *sec.GetValue(e); - CString name = *sec.GetValueName(e); - - sec.values.erase(name); - name.TrimLeft(); - sec.values[name] = value; - } - } - } -} - -void CIniFile::DeleteEndingSpaces(BOOL bValueNames, BOOL bValues) -{ - int i; - for (i = 0;i < sections.size();i++) - { - CIniFileSection& sec = *GetSection(i); - int e; - for (e = 0;e < sec.values.size();e++) - { - if (bValues) sec.GetValue(e)->TrimRight(); - if (bValueNames) - { - //CString& name=(CString&)*sec.GetValueName(e); - //name.TrimRight(); - CString value = *sec.GetValue(e); - CString name = *sec.GetValueName(e); - - sec.values.erase(name); - name.TrimRight(); - sec.values[name] = value; - } - } - } -} - CString CIniFile::GetValueByName(const CString& sectionName, const CString& valueName, const CString& defaultValue) const { - auto section = GetSection(sectionName); + auto section = TryGetSection(sectionName); if (!section) return defaultValue; return section->GetValueByName(valueName, defaultValue); diff --git a/MissionEditor/IniFile.h b/MissionEditor/IniFile.h index bc0b8b6..01162be 100644 --- a/MissionEditor/IniFile.h +++ b/MissionEditor/IniFile.h @@ -33,7 +33,10 @@ #include #include #include +#include +#include #include +#include "IniHelper.h" using namespace std; @@ -49,30 +52,92 @@ public: class CIniFileSection { public: + + static const CString EmptyValue; + CIniFileSection(); virtual ~CIniFileSection(); - CString GetValueByName(const CString& name, const CString& defaultValue = CString()) const; + [[deprecated("instead use GetString or TryGetString")]] CString& AccessValueByName(const CString& name); - auto begin() noexcept - { - return values.begin(); + auto const& Nth(size_t index) const { + ASSERT(index < value_pairs.size()); + return this->value_pairs[index]; + } + + const CString* TryGetString(const CString& key) const { + auto const it = value_pos.find(key); + if (it != value_pos.end()) { + return &this->value_pairs[it->second].second; + } + return nullptr; + } + + const CString& GetString(const CString& key) const { + if (auto const ret = TryGetString(key)) { + return *ret; + } + return EmptyValue; + } + CString GetStringOr(const CString& key, const CString& defaultValue) const { + auto const it = value_pos.find(key); + if (it != value_pos.end()) { + return this->value_pairs[it->second].second; + } + return defaultValue; + } + + int GetInteger(const CString& key, int def = 0)const { + return INIHelper::StringToInteger(this->GetString(key), def); + } + + size_t Size() const { return value_pos.size(); } + + bool Exists(const CString& key) const { + auto const it = value_pos.find(key); + return it != value_pos.end(); + } + + void Assign(const CString& key, const CString& value) { + return this->Assign(key, CString(value)); + } + + void Assign(const CString& key, CString&& value) { + auto const it = value_pos.find(key); + // new, never had one + if (it == value_pos.end()) { + this->value_pairs.push_back({ key, std::move(value) }); + value_pos[key] = value_pairs.size(); + return; + } + value_pairs[it->second].second = std::move(value); + } + + bool HasValue(const CString& val) const { + return this->FindValue(val) >= 0; + } + + void RemoveAt(size_t idx) { + ASSERT(idx < value_pairs.size()); + for (auto affectedIdx = idx + 1; affectedIdx < value_pairs.size(); ++affectedIdx) { + auto const& kvPair = value_pairs[affectedIdx]; + auto const it = value_pos.find(kvPair.first); + ASSERT(it != value_pos.end()); + it->second--; + } + auto const itErased = value_pairs.erase(value_pairs.begin() + idx); + ASSERT(value_pos.erase(itErased->first), 1); } auto begin() const noexcept { - return values.begin(); - } - - auto end() noexcept - { - return values.end(); + return value_pairs.begin(); } auto end() const noexcept { - return values.end(); + return value_pairs.end(); } [[deprecated("instead use iterators or for_each")]] @@ -87,28 +152,45 @@ public: [[deprecated("instead use iterators or for_each")]] const CString* GetValueName(std::size_t index) const noexcept; - [[deprecated("instead use iterators or for_each")]] - const CString* GetValue(std::size_t index) const noexcept; - - [[deprecated("instead use iterators or for_each")]] - CString* GetValue(std::size_t index) noexcept; - -public: - map values; - map value_orig_pos; +private: + map value_pos{}; + vector> value_pairs{};// sequenced + mutable bool isRegistry{false}; }; class CIniFile { + static const CIniFileSection EmptySection; + public: - void DeleteEndingSpaces(BOOL bValueNames, BOOL bValues); - void DeleteLeadingSpaces(BOOL bValueNames, BOOL bValues); - const CString* GetSectionName(std::size_t Index) const noexcept; - const CIniFileSection* GetSection(std::size_t index) const; - CIniFileSection* GetSection(std::size_t index); - const CIniFileSection* GetSection(const CString& section) const; - CIniFileSection* GetSection(const CString& section); + const CIniFileSection* TryGetSection(std::size_t index) const; + CIniFileSection* TryGetSection(std::size_t index); + + const CIniFileSection* TryGetSection(const CString& section) const + { + auto pMutThis = const_cast>*>(this); + return pMutThis->TryGetSection(section); + } + + CIniFileSection* TryGetSection(const CString& section) + { + auto it = sections.find(section); + if (it != sections.end()) { + return &it->second; + + } + return nullptr; + } + + const CIniFileSection& GetSection(const CString& section) const { + auto const it = sections.find(section); + if (it != sections.end()) { + return it->second; + } + return EmptySection; + } + CString GetValueByName(const CString& sectionName, const CString& valueName, const CString& defaultValue) const; void Clear(); WORD InsertFile(const CString& filename, const char* Section, BOOL bNoSpaces = FALSE); @@ -118,6 +200,32 @@ public: WORD LoadFile(const CString& filename, BOOL bNoSpaces = FALSE); WORD LoadFile(const std::string& filename, BOOL bNoSpaces = FALSE); + const CString& GetString(const CString& section, const CString& key) const { + auto const it = sections.find(section); + if (it != sections.end()) { + return it->second.GetString(key); + } + return CIniFileSection::EmptyValue; + } + const bool GetBool(const CString& section, const CString& key, bool def = false) const { + auto const& str = this->GetString(section, key); + return INIHelper::StingToBool(str, def); + } + + void Assign(const CString& section, const CString& key, CString&& value) { + auto const it = sections.find(section); + if (it != sections.end()) { + it->second.Assign(key, value); + return; + } + auto&& newSec = CIniFileSection{}; + newSec.Assign(key, value); + ASSERT(sections.insert({ key, std::move(newSec) }).second == true); + } + + void Assign(const CString& section, const CString& key, const CString& value) { + return this->Assign(section, key, CString(value)); + } auto begin() noexcept { @@ -139,12 +247,12 @@ public: return sections.end(); } - map sections; CIniFile(); virtual ~CIniFile(); private: std::string m_filename; + map sections; }; #endif // !defined(AFX_INIFILE_H__96455620_6528_11D3_99E0_DB2A1EF71411__INCLUDED_) diff --git a/MissionEditor/IniHelper.h b/MissionEditor/IniHelper.h new file mode 100644 index 0000000..3978793 --- /dev/null +++ b/MissionEditor/IniHelper.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include + +class INIHelper +{ +public: + static bool StingToBool(const CString& str, bool def) + { + switch (toupper(static_cast(*str))) { + case '1': + case 'T': + case 'Y': + return true; + case '0': + case 'F': + case 'N': + return false; + default: + return def; + } + } + static int StringToInteger(const CString& str, int def) + { + int ret = 0; + if (sscanf_s(str, "%d", &ret) == 1) { + return ret; + } + return def; + } +}; \ No newline at end of file