From f9da4e1f6615d6dc7fbdccd27df3d750d4798ccc Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 14 Nov 2022 09:43:47 +0000 Subject: [PATCH] assets.cpp: Avoid allocs in UNPACKED_MPQS FindFile --- Source/engine/assets.cpp | 48 ++++++++++++++++++++++++++-------------- Source/engine/assets.hpp | 8 ++++--- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/Source/engine/assets.cpp b/Source/engine/assets.cpp index c1045aaa3..6ea3b250f 100644 --- a/Source/engine/assets.cpp +++ b/Source/engine/assets.cpp @@ -9,21 +9,24 @@ #include "utils/file_util.h" #include "utils/log.hpp" #include "utils/paths.h" +#include "utils/str_cat.hpp" namespace devilution { namespace { #ifdef UNPACKED_MPQS -std::string FindUnpackedMpqFile(const char *relativePath) +char *FindUnpackedMpqFile(char *relativePath) { - std::string path; + char *path = nullptr; const auto at = [&](const std::optional &unpackedDir) -> bool { if (!unpackedDir) return false; - if (FileExists(path.append(*unpackedDir).append(relativePath).c_str())) + path = relativePath - unpackedDir->size(); + std::memcpy(path, unpackedDir->data(), unpackedDir->size()); + if (FileExists(path)) return true; - path.clear(); + path = nullptr; return false; }; at(font_data_path) || at(lang_data_path) @@ -68,26 +71,39 @@ bool FindMpqFile(const char *filename, MpqArchive **archive, uint32_t *fileNumbe AssetRef FindAsset(const char *filename) { AssetRef result; - std::string relativePath = filename; + result.path[0] = '\0'; + + const string_view filenameStr = filename; + char pathBuf[AssetRef::PathBufSize]; + char *const pathEnd = pathBuf + AssetRef::PathBufSize; + char *const relativePath = &pathBuf[AssetRef::PathBufSize - filenameStr.size() - 1]; + *BufCopy(relativePath, filenameStr) = '\0'; + #ifndef _WIN32 - std::replace(relativePath.begin(), relativePath.end(), '\\', '/'); + std::replace(relativePath, pathEnd, '\\', '/'); #endif // Absolute path: if (relativePath[0] == '/') { - if (FileExists(relativePath)) - result.path = std::move(relativePath); + if (FileExists(relativePath)) { + *BufCopy(result.path, string_view(relativePath, filenameStr.size())) = '\0'; + } return result; } // Unpacked MPQ file: - result.path = FindUnpackedMpqFile(relativePath.c_str()); - if (!result.path.empty()) + char *const unpackedMpqPath = FindUnpackedMpqFile(relativePath); + if (unpackedMpqPath != nullptr) { + *BufCopy(result.path, string_view(unpackedMpqPath, pathEnd - unpackedMpqPath)) = '\0'; return result; + } // The `/assets` directory next to the devilutionx binary. - std::string path = paths::AssetsPath() + relativePath; - if (FileExists(path)) - result.path = std::move(path); + const std::string &assetsPathPrefix = paths::AssetsPath(); + char *assetsPath = relativePath - assetsPathPrefix.size(); + std::memcpy(assetsPath, assetsPathPrefix.data(), assetsPathPrefix.size()); + if (FileExists(assetsPath)) { + *BufCopy(result.path, string_view(assetsPath, pathEnd - assetsPath)) = '\0'; + } return result; } #else @@ -143,8 +159,8 @@ AssetRef FindAsset(const char *filename) AssetHandle OpenAsset(AssetRef &&ref, bool threadsafe) { -#ifdef UNPACKED_MPQS - return AssetHandle { OpenFile(ref.path.c_str(), "rb") }; +#if UNPACKED_MPQS + return AssetHandle { OpenFile(ref.path, "rb") }; #else if (ref.archive != nullptr) return AssetHandle { SDL_RWops_FromMpqFile(*ref.archive, ref.fileNumber, ref.filename, threadsafe) }; @@ -181,7 +197,7 @@ SDL_RWops *OpenAssetAsSdlRwOps(const char *filename, bool threadsafe) AssetRef ref = FindAsset(filename); if (!ref.ok()) return nullptr; - return SDL_RWFromFile(ref.path.c_str(), "rb"); + return SDL_RWFromFile(ref.path, "rb"); #else return OpenAsset(filename, threadsafe).release(); #endif diff --git a/Source/engine/assets.hpp b/Source/engine/assets.hpp index 34ac808b4..2b9fd89fd 100644 --- a/Source/engine/assets.hpp +++ b/Source/engine/assets.hpp @@ -18,11 +18,13 @@ namespace devilution { #ifdef UNPACKED_MPQS struct AssetRef { - std::string path; + static constexpr size_t PathBufSize = 4088; + + char path[PathBufSize]; [[nodiscard]] bool ok() const { - return !path.empty(); + return path[0] != '\0'; } // NOLINTNEXTLINE(readability-convert-member-functions-to-static) @@ -34,7 +36,7 @@ struct AssetRef { [[nodiscard]] size_t size() const { uintmax_t fileSize; - if (!GetFileSize(path.c_str(), &fileSize)) + if (!GetFileSize(path, &fileSize)) return 0; return fileSize; }