From 2105e98d0ab283b7fd8cc621a75cc7ba01dca4c2 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 1 Sep 2025 17:08:33 +0200 Subject: [PATCH 1/2] Use std::string_view in collections --- components/files/collections.cpp | 14 ++++++-------- components/files/collections.hpp | 11 +++++------ components/files/multidircollection.cpp | 10 +++++----- components/files/multidircollection.hpp | 7 +++---- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/components/files/collections.cpp b/components/files/collections.cpp index a1b444a746..6c70c0d3b9 100644 --- a/components/files/collections.cpp +++ b/components/files/collections.cpp @@ -18,14 +18,12 @@ namespace Files { } - const MultiDirCollection& Collections::getCollection(const std::string& extension) const + const MultiDirCollection& Collections::getCollection(std::string_view extension) const { - std::string ext = Misc::StringUtils::lowerCase(extension); - auto iter = mCollections.find(ext); + auto iter = mCollections.find(extension); if (iter == mCollections.end()) { - std::pair result - = mCollections.emplace(ext, MultiDirCollection(mDirectories, ext)); + auto result = mCollections.emplace(extension, MultiDirCollection(mDirectories, extension)); iter = result.first; } @@ -33,7 +31,7 @@ namespace Files return iter->second; } - std::filesystem::path Collections::getPath(const std::string& file) const + std::filesystem::path Collections::getPath(std::string_view file) const { for (auto iter = mDirectories.rbegin(); iter != mDirectories.rend(); iter++) { @@ -47,10 +45,10 @@ namespace Files } } - throw std::runtime_error("file " + file + " not found"); + throw std::runtime_error("file " + std::string(file) + " not found"); } - bool Collections::doesExist(const std::string& file) const + bool Collections::doesExist(std::string_view file) const { for (auto iter = mDirectories.rbegin(); iter != mDirectories.rend(); iter++) { diff --git a/components/files/collections.hpp b/components/files/collections.hpp index 88e047aa45..e87eab3e44 100644 --- a/components/files/collections.hpp +++ b/components/files/collections.hpp @@ -16,26 +16,25 @@ namespace Files Collections(const Files::PathContainer& directories); ///< Return a file collection for the given extension. Extension must contain the - /// leading dot and must be all lower-case. - const MultiDirCollection& getCollection(const std::string& extension) const; + /// leading dot + const MultiDirCollection& getCollection(std::string_view extension) const; - std::filesystem::path getPath(const std::string& file) const; + std::filesystem::path getPath(std::string_view file) const; ///< Return full path (including filename) of \a file. /// /// If the file does not exist in any of the collection's /// directories, an exception is thrown. \a file must include the /// extension. - bool doesExist(const std::string& file) const; + bool doesExist(std::string_view file) const; ///< \return Does a file with the given name exist? const Files::PathContainer& getPaths() const; private: - typedef std::map MultiDirCollectionContainer; Files::PathContainer mDirectories; - mutable MultiDirCollectionContainer mCollections; + mutable std::map mCollections; }; } diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 16c9251f24..dda5f17d1c 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -8,7 +8,7 @@ namespace Files { - MultiDirCollection::MultiDirCollection(const Files::PathContainer& directories, const std::string& extension) + MultiDirCollection::MultiDirCollection(const Files::PathContainer& directories, std::string_view extension) { for (const auto& directory : directories) { @@ -47,19 +47,19 @@ namespace Files } } - std::filesystem::path MultiDirCollection::getPath(const std::string& file) const + std::filesystem::path MultiDirCollection::getPath(std::string_view file) const { TIter iter = mFiles.find(file); if (iter == mFiles.end()) - throw std::runtime_error("file " + file + " not found"); + throw std::runtime_error("file " + std::string(file) + " not found"); return iter->second; } - bool MultiDirCollection::doesExist(const std::string& file) const + bool MultiDirCollection::doesExist(std::string_view file) const { - return mFiles.find(file) != mFiles.end(); + return mFiles.contains(file); } MultiDirCollection::TIter MultiDirCollection::begin() const diff --git a/components/files/multidircollection.hpp b/components/files/multidircollection.hpp index f6549f9ddb..aae681a743 100644 --- a/components/files/multidircollection.hpp +++ b/components/files/multidircollection.hpp @@ -28,19 +28,18 @@ namespace Files TContainer mFiles; public: - MultiDirCollection(const Files::PathContainer& directories, const std::string& extension); + MultiDirCollection(const Files::PathContainer& directories, std::string_view extension); ///< Directories are listed with increasing priority. /// \param extension The extension that should be listed in this collection. Must /// contain the leading dot. - /// \param foldCase Ignore filename case - std::filesystem::path getPath(const std::string& file) const; + std::filesystem::path getPath(std::string_view file) const; ///< Return full path (including filename) of \a file. /// /// If the file does not exist, an exception is thrown. \a file must include /// the extension. - bool doesExist(const std::string& file) const; + bool doesExist(std::string_view file) const; ///< \return Does a file with the given name exist? TIter begin() const; From 14e1ec6d8726f831b8f2e2c25a38b52e6f6482c4 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 1 Sep 2025 17:57:44 +0200 Subject: [PATCH 2/2] Use pathhelpers to populate Collections --- apps/components_tests/esm3/readerscache.cpp | 2 +- apps/niftest/niftest.cpp | 4 +-- apps/openmw/mwworld/worldimp.cpp | 5 ++-- components/esmloader/load.cpp | 18 +++++++------- components/files/collections.cpp | 1 - components/files/collections.hpp | 3 +-- components/files/multidircollection.cpp | 5 ++-- components/translation/translation.cpp | 27 +++++++++++---------- components/translation/translation.hpp | 2 +- 9 files changed, 33 insertions(+), 34 deletions(-) diff --git a/apps/components_tests/esm3/readerscache.cpp b/apps/components_tests/esm3/readerscache.cpp index 1cb9a85fb6..303495a0ed 100644 --- a/apps/components_tests/esm3/readerscache.cpp +++ b/apps/components_tests/esm3/readerscache.cpp @@ -42,7 +42,7 @@ namespace const Files::PathContainer mDataDirs{ { std::filesystem::path{ OPENMW_DATA_DIR } } }; const Files::Collections mFileCollections{ mDataDirs }; const std::string mContentFile = "template.omwgame"; - const std::filesystem::path mContentFilePath = mFileCollections.getCollection(".omwgame").getPath(mContentFile); + const std::filesystem::path mContentFilePath = mFileCollections.getCollection("omwgame").getPath(mContentFile); }; TEST_F(ESM3ReadersCacheWithContentFile, shouldKeepOpenReleasedOpenReader) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 4afa0a04f4..dbff004875 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -190,8 +190,8 @@ void readVFS(std::unique_ptr&& archive, const std::filesystem::pat if (!archivePath.empty() && !isBSA(archivePath)) { const Files::Collections fileCollections({ archivePath }); - const Files::MultiDirCollection& bsaCol = fileCollections.getCollection(".bsa"); - const Files::MultiDirCollection& ba2Col = fileCollections.getCollection(".ba2"); + const Files::MultiDirCollection& bsaCol = fileCollections.getCollection("bsa"); + const Files::MultiDirCollection& ba2Col = fileCollections.getCollection("ba2"); for (const Files::MultiDirCollection& collection : { bsaCol, ba2Col }) { for (auto& file : collection) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 957ab98f24..08504efc6a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -2885,9 +2886,7 @@ namespace MWWorld int idx = 0; for (const std::string& file : content) { - const auto filename = Files::pathFromUnicodeString(file); - const Files::MultiDirCollection& col - = fileCollections.getCollection(Files::pathToUnicodeString(filename.extension())); + const Files::MultiDirCollection& col = fileCollections.getCollection(Misc::getFileExtension(file)); if (col.doesExist(file)) { gameContentLoader.load(col.getPath(file), idx, listener); diff --git a/components/esmloader/load.cpp b/components/esmloader/load.cpp index 5b1888f2ce..2c13f9acf1 100644 --- a/components/esmloader/load.cpp +++ b/components/esmloader/load.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -211,21 +212,20 @@ namespace EsmLoader { ShallowContent result; - const std::set supportedFormats{ - ".esm", - ".esp", - ".omwgame", - ".omwaddon", - ".project", + const std::set supportedFormats{ + "esm", + "esp", + "omwgame", + "omwaddon", + "project", }; for (std::size_t i = 0; i < contentFiles.size(); ++i) { const std::string& file = contentFiles[i]; - const std::string extension - = Misc::StringUtils::lowerCase(Files::pathToUnicodeString(std::filesystem::path(file).extension())); + const std::string_view extension = Misc::getFileExtension(file); - if (supportedFormats.find(extension) == supportedFormats.end()) + if (!supportedFormats.contains(extension)) { Log(Debug::Warning) << "Skipping unsupported content file: " << file; continue; diff --git a/components/files/collections.cpp b/components/files/collections.cpp index 6c70c0d3b9..4f147168aa 100644 --- a/components/files/collections.cpp +++ b/components/files/collections.cpp @@ -2,7 +2,6 @@ #include "conversion.hpp" #include -#include namespace Files { diff --git a/components/files/collections.hpp b/components/files/collections.hpp index e87eab3e44..7ebb72ae67 100644 --- a/components/files/collections.hpp +++ b/components/files/collections.hpp @@ -15,8 +15,7 @@ namespace Files ///< Directories are listed with increasing priority. Collections(const Files::PathContainer& directories); - ///< Return a file collection for the given extension. Extension must contain the - /// leading dot + ///< Return a file collection for the given extension. const MultiDirCollection& getCollection(std::string_view extension) const; std::filesystem::path getPath(std::string_view file) const; diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index dda5f17d1c..157923a531 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -22,7 +22,8 @@ namespace Files { const auto& path = dirIter.path(); - if (!Misc::StringUtils::ciEqual(extension, Files::pathToUnicodeString(path.extension()))) + std::string ext = Files::pathToUnicodeString(path.extension()); + if (ext.size() != extension.size() + 1 || !Misc::StringUtils::ciEndsWith(ext, extension)) continue; const auto filename = Files::pathToUnicodeString(path.filename()); @@ -41,7 +42,7 @@ namespace Files { // handle case folding mFiles.erase(result->first); - mFiles.insert(std::make_pair(filename, path)); + mFiles.emplace(filename, path); } } } diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index 36cca02fcc..2935c337b4 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -2,6 +2,8 @@ #include +#include + namespace Translation { Storage::Storage() @@ -11,25 +13,24 @@ namespace Translation void Storage::loadTranslationData(const Files::Collections& dataFileCollections, std::string_view esmFileName) { - std::string esmNameNoExtension(Misc::StringUtils::lowerCase(esmFileName)); - // changing the extension - size_t dotPos = esmNameNoExtension.rfind('.'); - if (dotPos != std::string::npos) - esmNameNoExtension.resize(dotPos); + std::string_view esmNameNoExtension = Misc::stemFile(esmFileName); - loadData(mCellNamesTranslations, esmNameNoExtension, ".cel", dataFileCollections); - loadData(mPhraseForms, esmNameNoExtension, ".top", dataFileCollections); - loadData(mTopicIDs, esmNameNoExtension, ".mrk", dataFileCollections); + loadData(mCellNamesTranslations, esmNameNoExtension, "cel", dataFileCollections); + loadData(mPhraseForms, esmNameNoExtension, "top", dataFileCollections); + loadData(mTopicIDs, esmNameNoExtension, "mrk", dataFileCollections); } - void Storage::loadData(ContainerType& container, const std::string& fileNameNoExtension, - const std::string& extension, const Files::Collections& dataFileCollections) + void Storage::loadData(ContainerType& container, std::string_view fileNameNoExtension, std::string_view extension, + const Files::Collections& dataFileCollections) { - std::string fileName = fileNameNoExtension + extension; + std::string fileName(fileNameNoExtension); + fileName += '.'; + fileName += extension; - if (dataFileCollections.getCollection(extension).doesExist(fileName)) + const Files::MultiDirCollection& collection = dataFileCollections.getCollection(extension); + if (collection.doesExist(fileName)) { - std::ifstream stream(dataFileCollections.getCollection(extension).getPath(fileName).c_str()); + std::ifstream stream(collection.getPath(fileName)); if (!stream.is_open()) throw std::runtime_error("failed to open translation file: " + fileName); diff --git a/components/translation/translation.hpp b/components/translation/translation.hpp index 18e40713e5..1473e9eeca 100644 --- a/components/translation/translation.hpp +++ b/components/translation/translation.hpp @@ -26,7 +26,7 @@ namespace Translation private: typedef std::map> ContainerType; - void loadData(ContainerType& container, const std::string& fileNameNoExtension, const std::string& extension, + void loadData(ContainerType& container, std::string_view fileNameNoExtension, std::string_view extension, const Files::Collections& dataFileCollections); void loadDataFromStream(ContainerType& container, std::istream& stream);