Use map for IWD entries to speed up finding entries by name

This commit is contained in:
Jan 2020-10-17 14:59:36 +02:00
parent a1c965a4c0
commit 395c139681

View File

@ -7,6 +7,7 @@
#include <unzip.h> #include <unzip.h>
#include <filesystem> #include <filesystem>
#include <cassert> #include <cassert>
#include <map>
ObjContainerRepository<IWD, ISearchPath> IWD::Repository; ObjContainerRepository<IWD, ISearchPath> IWD::Repository;
@ -125,8 +126,7 @@ class IWD::Impl : public ISearchPath, public IObjContainer, public IWDFile::IPar
class IWDEntry class IWDEntry
{ {
public: public:
std::string m_name; size_t m_size{};
size_t m_size;
unz_file_pos m_file_pos{}; unz_file_pos m_file_pos{};
}; };
@ -136,7 +136,7 @@ class IWD::Impl : public ISearchPath, public IObjContainer, public IWDFile::IPar
IWDFile* m_last_file; IWDFile* m_last_file;
std::vector<IWDEntry> m_entries; std::map<std::string, IWDEntry> m_entry_map;
public: public:
Impl(std::string path, FileAPI::IFile* file) Impl(std::string path, FileAPI::IFile* file)
@ -147,7 +147,7 @@ public:
m_last_file = nullptr; m_last_file = nullptr;
} }
~Impl() ~Impl() override
{ {
if (m_unz_file != nullptr) if (m_unz_file != nullptr)
{ {
@ -162,6 +162,11 @@ public:
} }
} }
Impl(const Impl& other) = delete;
Impl(Impl&& other) noexcept = default;
Impl& operator=(const Impl& other) = delete;
Impl& operator=(Impl&& other) noexcept = default;
bool Initialize() bool Initialize()
{ {
auto ioFunctions = FileToZlibWrapper::CreateFunctions32ForFile(m_file); auto ioFunctions = FileToZlibWrapper::CreateFunctions32ForFile(m_file);
@ -186,10 +191,9 @@ public:
if (path.has_filename()) if (path.has_filename())
{ {
IWDEntry entry; IWDEntry entry;
entry.m_name = std::move(fileName);
entry.m_size = info.uncompressed_size; entry.m_size = info.uncompressed_size;
unzGetFilePos(m_unz_file, &entry.m_file_pos); unzGetFilePos(m_unz_file, &entry.m_file_pos);
m_entries.push_back(entry); m_entry_map.emplace(std::move(fileName), entry);
} }
ret = unzGoToNextFile(m_unz_file); ret = unzGoToNextFile(m_unz_file);
@ -197,7 +201,7 @@ public:
if (ObjLoading::Configuration.Verbose) if (ObjLoading::Configuration.Verbose)
{ {
printf("Loaded IWD \"%s\" with %u entries\n", m_path.c_str(), m_entries.size()); printf("Loaded IWD \"%s\" with %u entries\n", m_path.c_str(), m_entry_map.size());
} }
return true; return true;
@ -213,24 +217,21 @@ public:
std::string iwdFilename = fileName; std::string iwdFilename = fileName;
std::replace(iwdFilename.begin(), iwdFilename.end(), '\\', '/'); std::replace(iwdFilename.begin(), iwdFilename.end(), '\\', '/');
const auto iwdEntry = std::find_if(m_entries.begin(), m_entries.end(), [&iwdFilename](IWDEntry& entry) -> bool const auto iwdEntry = m_entry_map.find(iwdFilename);
{
return entry.m_name == iwdFilename;
});
if (iwdEntry != m_entries.end()) if (iwdEntry != m_entry_map.end())
{ {
if(m_last_file != nullptr) if(m_last_file != nullptr)
{ {
throw std::runtime_error("Trying to open new IWD file while last one was not yet closed."); throw std::runtime_error("Trying to open new IWD file while last one was not yet closed.");
} }
auto pos = iwdEntry->m_file_pos; auto pos = iwdEntry->second.m_file_pos;
unzGoToFilePos(m_unz_file, &pos); unzGoToFilePos(m_unz_file, &pos);
if (unzOpenCurrentFile(m_unz_file) == UNZ_OK) if (unzOpenCurrentFile(m_unz_file) == UNZ_OK)
{ {
m_last_file = new IWDFile(this, m_unz_file, iwdEntry->m_size); m_last_file = new IWDFile(this, m_unz_file, iwdEntry->second.m_size);
} }
return m_last_file; return m_last_file;
@ -256,9 +257,9 @@ public:
return; return;
} }
for(auto& entry : m_entries) for(auto& entry : m_entry_map)
{ {
std::filesystem::path entryPath(entry.m_name); std::filesystem::path entryPath(entry.first);
if(!options.m_should_include_subdirectories && entryPath.has_parent_path()) if(!options.m_should_include_subdirectories && entryPath.has_parent_path())
continue; continue;
@ -266,7 +267,7 @@ public:
if(options.m_filter_extensions && options.m_extension != entryPath.extension().string()) if(options.m_filter_extensions && options.m_extension != entryPath.extension().string())
continue; continue;
callback(entry.m_name); callback(entry.first);
} }
} }