diff --git a/src/api/game/game.cpp b/src/api/game/game.cpp index 4bc1279e..7b599033 100644 --- a/src/api/game/game.cpp +++ b/src/api/game/game.cpp @@ -153,7 +153,6 @@ void Game::LoadPlugins(const std::vector& plugins, // Clear the existing plugin and archive caches. cache_->ClearCachedPlugins(); - cache_->ClearCachedArchivePaths(); // Search for and cache archives. CacheArchives(); @@ -243,17 +242,20 @@ void Game::SetLoadOrder(const std::vector& loadOrder) { void Game::CacheArchives() { const auto archiveFileExtension = GetArchiveFileExtension(Type()); + std::set archivePaths; for (std::filesystem::directory_iterator it(DataPath()); it != std::filesystem::directory_iterator(); ++it) { - // Check if the path is an archive by checking if replacing its - // file extension with the archive extension resolves to the same file. - // Could use boost::iends_with, but it's less obvious here that the - // test string is ASCII-only. - if (loot::equivalent(it->path(), - replaceExtension(it->path(), archiveFileExtension))) { - cache_->CacheArchivePath(it->path()); + // This is only correct for ASCII strings, but that's all that + // GetArchiveFileExtension() can return. It's a lot faster than the more + // generally-correct approach of testing file path equivalence when + // there are a lot of entries in DataPath(). + if (it->is_regular_file() && + boost::iends_with(it->path().u8string(), archiveFileExtension)) { + archivePaths.insert(it->path()); } } + + cache_->CacheArchivePaths(std::move(archivePaths)); } } diff --git a/src/api/game/game_cache.cpp b/src/api/game/game_cache.cpp index 8a8f2f2d..f76f3110 100644 --- a/src/api/game/game_cache.cpp +++ b/src/api/game/game_cache.cpp @@ -36,8 +36,7 @@ using std::string; namespace loot { GameCache::GameCache() {} -GameCache::GameCache(const GameCache& cache) : - plugins_(cache.plugins_) {} +GameCache::GameCache(const GameCache& cache) : plugins_(cache.plugins_) {} GameCache& GameCache::operator=(const GameCache& cache) { if (&cache != this) { @@ -78,20 +77,17 @@ void GameCache::AddPlugin(const Plugin&& plugin) { if (it != end(plugins_)) plugins_.erase(it); - plugins_.emplace(normalizedName, - std::make_shared(std::move(plugin))); + plugins_.emplace(normalizedName, std::make_shared(std::move(plugin))); } -std::set GameCache::GetArchivePaths() const -{ +std::set GameCache::GetArchivePaths() const { return archivePaths_; } -void GameCache::CacheArchivePath(const std::filesystem::path& path) -{ +void GameCache::CacheArchivePaths(std::set&& paths) { lock_guard lock(mutex_); - archivePaths_.insert(path); + archivePaths_ = paths; } void GameCache::ClearCachedPlugins() { @@ -99,10 +95,4 @@ void GameCache::ClearCachedPlugins() { plugins_.clear(); } - -void GameCache::ClearCachedArchivePaths() { - lock_guard guard(mutex_); - - archivePaths_.clear(); -} } diff --git a/src/api/game/game_cache.h b/src/api/game/game_cache.h index caf3a851..48ed86fe 100644 --- a/src/api/game/game_cache.h +++ b/src/api/game/game_cache.h @@ -44,10 +44,9 @@ public: void AddPlugin(const Plugin&& plugin); std::set GetArchivePaths() const; - void CacheArchivePath(const std::filesystem::path& path); + void CacheArchivePaths(std::set&& paths); void ClearCachedPlugins(); - void ClearCachedArchivePaths(); private: std::unordered_map> plugins_; diff --git a/src/tests/api/internals/game/game_cache_test.h b/src/tests/api/internals/game/game_cache_test.h index 74b5260a..a49702b8 100644 --- a/src/tests/api/internals/game/game_cache_test.h +++ b/src/tests/api/internals/game/game_cache_test.h @@ -113,8 +113,8 @@ TEST_P(GameCacheTest, TEST_P(GameCacheTest, gettingArchivePathsShouldReturnASetOfPathsIfPathsHaveBeenCached) { - cache_.CacheArchivePath(game_.DataPath() / blankEsm); - cache_.CacheArchivePath(game_.DataPath() / blankMasterDependentEsm); + cache_.CacheArchivePaths({game_.DataPath() / blankEsm, + game_.DataPath() / blankMasterDependentEsm}); auto expected = std::set({ game_.DataPath() / blankEsm, @@ -137,18 +137,6 @@ TEST_P(GameCacheTest, clearingCachedPluginsShouldClearAnyCachedPlugins) { EXPECT_TRUE(cache_.GetPlugins().empty()); } - -TEST_P(GameCacheTest, - clearingCachedArchivePathsShouldNotThrowIfNoPathsAreCached) { - EXPECT_NO_THROW(cache_.GetArchivePaths()); -} - -TEST_P(GameCacheTest, clearingCachedArchivePathsShouldClearAnyCachedPaths) { - cache_.CacheArchivePath(game_.DataPath() / blankEsm); - cache_.ClearCachedArchivePaths(); - - EXPECT_TRUE(cache_.GetArchivePaths().empty()); -} } } diff --git a/src/tests/api/internals/plugin_test.h b/src/tests/api/internals/plugin_test.h index 54524911..1bc40c61 100644 --- a/src/tests/api/internals/plugin_test.h +++ b/src/tests/api/internals/plugin_test.h @@ -91,10 +91,10 @@ protected: out.open(nonAsciiPrefixArchivePath); out.close(); - game_.GetCache()->CacheArchivePath(dataPath / blankArchive); - game_.GetCache()->CacheArchivePath(dataPath / blankSuffixArchive); - game_.GetCache()->CacheArchivePath(dataPath / nonAsciiArchivePath); - game_.GetCache()->CacheArchivePath(dataPath / nonAsciiPrefixArchivePath); + game_.GetCache()->CacheArchivePaths({dataPath / blankArchive, + dataPath / blankSuffixArchive, + dataPath / nonAsciiArchivePath, + dataPath / nonAsciiPrefixArchivePath}); } uintmax_t getGhostedPluginFileSize() {