Merge pull request #11774 from liamwhite/refcount-issue
fsmitm_romfsbuild: avoid unnecessary copies of vfs pointers
This commit is contained in:
		@@ -116,11 +116,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (concat.empty()) {
 | 
			
		||||
            return nullptr;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
 | 
			
		||||
        return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(dir->GetName(),
 | 
			
		||||
                                                                  std::move(concat));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (Common::FS::IsDir(path)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -107,62 +107,56 @@ static u64 romfs_get_hash_table_count(u64 num_entries) {
 | 
			
		||||
 | 
			
		||||
void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir,
 | 
			
		||||
                                       std::shared_ptr<RomFSBuildDirectoryContext> parent) {
 | 
			
		||||
    std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs;
 | 
			
		||||
    for (auto& child_romfs_file : romfs_dir->GetFiles()) {
 | 
			
		||||
        const auto name = child_romfs_file->GetName();
 | 
			
		||||
        const auto child = std::make_shared<RomFSBuildFileContext>();
 | 
			
		||||
        // Set child's path.
 | 
			
		||||
        child->cur_path_ofs = parent->path_len + 1;
 | 
			
		||||
        child->path_len = child->cur_path_ofs + static_cast<u32>(name.size());
 | 
			
		||||
        child->path = parent->path + "/" + name;
 | 
			
		||||
 | 
			
		||||
    const auto entries = romfs_dir->GetEntries();
 | 
			
		||||
        if (ext_dir != nullptr && ext_dir->GetFile(name + ".stub") != nullptr) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    for (const auto& kv : entries) {
 | 
			
		||||
        if (kv.second == VfsEntryType::Directory) {
 | 
			
		||||
            const auto child = std::make_shared<RomFSBuildDirectoryContext>();
 | 
			
		||||
            // Set child's path.
 | 
			
		||||
            child->cur_path_ofs = parent->path_len + 1;
 | 
			
		||||
            child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
 | 
			
		||||
            child->path = parent->path + "/" + kv.first;
 | 
			
		||||
        // Sanity check on path_len
 | 
			
		||||
        ASSERT(child->path_len < FS_MAX_PATH);
 | 
			
		||||
 | 
			
		||||
            if (ext_dir != nullptr && ext_dir->GetFile(kv.first + ".stub") != nullptr) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        child->source = std::move(child_romfs_file);
 | 
			
		||||
 | 
			
		||||
            // Sanity check on path_len
 | 
			
		||||
            ASSERT(child->path_len < FS_MAX_PATH);
 | 
			
		||||
 | 
			
		||||
            if (AddDirectory(parent, child)) {
 | 
			
		||||
                child_dirs.push_back(child);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            const auto child = std::make_shared<RomFSBuildFileContext>();
 | 
			
		||||
            // Set child's path.
 | 
			
		||||
            child->cur_path_ofs = parent->path_len + 1;
 | 
			
		||||
            child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
 | 
			
		||||
            child->path = parent->path + "/" + kv.first;
 | 
			
		||||
 | 
			
		||||
            if (ext_dir != nullptr && ext_dir->GetFile(kv.first + ".stub") != nullptr) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Sanity check on path_len
 | 
			
		||||
            ASSERT(child->path_len < FS_MAX_PATH);
 | 
			
		||||
 | 
			
		||||
            child->source = romfs_dir->GetFile(kv.first);
 | 
			
		||||
 | 
			
		||||
            if (ext_dir != nullptr) {
 | 
			
		||||
                if (const auto ips = ext_dir->GetFile(kv.first + ".ips")) {
 | 
			
		||||
                    if (auto patched = PatchIPS(child->source, ips)) {
 | 
			
		||||
                        child->source = std::move(patched);
 | 
			
		||||
                    }
 | 
			
		||||
        if (ext_dir != nullptr) {
 | 
			
		||||
            if (const auto ips = ext_dir->GetFile(name + ".ips")) {
 | 
			
		||||
                if (auto patched = PatchIPS(child->source, ips)) {
 | 
			
		||||
                    child->source = std::move(patched);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            child->size = child->source->GetSize();
 | 
			
		||||
 | 
			
		||||
            AddFile(parent, child);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        child->size = child->source->GetSize();
 | 
			
		||||
 | 
			
		||||
        AddFile(parent, child);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (auto& child : child_dirs) {
 | 
			
		||||
        auto subdir_name = std::string_view(child->path).substr(child->cur_path_ofs);
 | 
			
		||||
        auto child_romfs_dir = romfs_dir->GetSubdirectory(subdir_name);
 | 
			
		||||
        auto child_ext_dir = ext_dir != nullptr ? ext_dir->GetSubdirectory(subdir_name) : nullptr;
 | 
			
		||||
    for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) {
 | 
			
		||||
        const auto name = child_romfs_dir->GetName();
 | 
			
		||||
        const auto child = std::make_shared<RomFSBuildDirectoryContext>();
 | 
			
		||||
        // Set child's path.
 | 
			
		||||
        child->cur_path_ofs = parent->path_len + 1;
 | 
			
		||||
        child->path_len = child->cur_path_ofs + static_cast<u32>(name.size());
 | 
			
		||||
        child->path = parent->path + "/" + name;
 | 
			
		||||
 | 
			
		||||
        if (ext_dir != nullptr && ext_dir->GetFile(name + ".stub") != nullptr) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Sanity check on path_len
 | 
			
		||||
        ASSERT(child->path_len < FS_MAX_PATH);
 | 
			
		||||
 | 
			
		||||
        if (!AddDirectory(parent, child)) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto child_ext_dir = ext_dir != nullptr ? ext_dir->GetSubdirectory(name) : nullptr;
 | 
			
		||||
        this->VisitDirectory(child_romfs_dir, child_ext_dir, child);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -293,7 +287,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
 | 
			
		||||
 | 
			
		||||
        cur_entry.name_size = name_size;
 | 
			
		||||
 | 
			
		||||
        out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source);
 | 
			
		||||
        out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source));
 | 
			
		||||
        std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry));
 | 
			
		||||
        std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0,
 | 
			
		||||
                    Common::AlignUp(cur_entry.name_size, 4));
 | 
			
		||||
 
 | 
			
		||||
@@ -377,16 +377,16 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
 | 
			
		||||
 | 
			
		||||
        auto romfs_dir = FindSubdirectoryCaseless(subdir, "romfs");
 | 
			
		||||
        if (romfs_dir != nullptr)
 | 
			
		||||
            layers.push_back(std::make_shared<CachedVfsDirectory>(romfs_dir));
 | 
			
		||||
            layers.emplace_back(std::make_shared<CachedVfsDirectory>(std::move(romfs_dir)));
 | 
			
		||||
 | 
			
		||||
        auto ext_dir = FindSubdirectoryCaseless(subdir, "romfs_ext");
 | 
			
		||||
        if (ext_dir != nullptr)
 | 
			
		||||
            layers_ext.push_back(std::make_shared<CachedVfsDirectory>(ext_dir));
 | 
			
		||||
            layers_ext.emplace_back(std::make_shared<CachedVfsDirectory>(std::move(ext_dir)));
 | 
			
		||||
 | 
			
		||||
        if (type == ContentRecordType::HtmlDocument) {
 | 
			
		||||
            auto manual_dir = FindSubdirectoryCaseless(subdir, "manual_html");
 | 
			
		||||
            if (manual_dir != nullptr)
 | 
			
		||||
                layers.push_back(std::make_shared<CachedVfsDirectory>(manual_dir));
 | 
			
		||||
                layers.emplace_back(std::make_shared<CachedVfsDirectory>(std::move(manual_dir)));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -400,7 +400,7 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    layers.push_back(std::move(extracted));
 | 
			
		||||
    layers.emplace_back(std::move(extracted));
 | 
			
		||||
 | 
			
		||||
    auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
 | 
			
		||||
    if (layered == nullptr) {
 | 
			
		||||
 
 | 
			
		||||
@@ -322,7 +322,8 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& open_di
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
 | 
			
		||||
    auto name = concat.front()->GetName();
 | 
			
		||||
    return ConcatenatedVfsFile::MakeConcatenatedFile(std::move(name), std::move(concat));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
 | 
			
		||||
 
 | 
			
		||||
@@ -133,7 +133,7 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) {
 | 
			
		||||
        out = out->GetSubdirectories().front();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return std::make_shared<CachedVfsDirectory>(out);
 | 
			
		||||
    return std::make_shared<CachedVfsDirectory>(std::move(out));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
 | 
			
		||||
@@ -141,8 +141,7 @@ VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
 | 
			
		||||
    RomFSBuildContext ctx{dir, ext};
 | 
			
		||||
    auto file_map = ctx.Build();
 | 
			
		||||
    return ConcatenatedVfsFile::MakeConcatenatedFile(0, file_map, dir->GetName());
 | 
			
		||||
    return ConcatenatedVfsFile::MakeConcatenatedFile(0, dir->GetName(), ctx.Build());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace FileSys
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,13 @@
 | 
			
		||||
 | 
			
		||||
namespace FileSys {
 | 
			
		||||
 | 
			
		||||
CachedVfsDirectory::CachedVfsDirectory(VirtualDir& source_dir)
 | 
			
		||||
CachedVfsDirectory::CachedVfsDirectory(VirtualDir&& source_dir)
 | 
			
		||||
    : name(source_dir->GetName()), parent(source_dir->GetParentDirectory()) {
 | 
			
		||||
    for (auto& dir : source_dir->GetSubdirectories()) {
 | 
			
		||||
        dirs.emplace(dir->GetName(), std::make_shared<CachedVfsDirectory>(dir));
 | 
			
		||||
        dirs.emplace(dir->GetName(), std::make_shared<CachedVfsDirectory>(std::move(dir)));
 | 
			
		||||
    }
 | 
			
		||||
    for (auto& file : source_dir->GetFiles()) {
 | 
			
		||||
        files.emplace(file->GetName(), file);
 | 
			
		||||
        files.emplace(file->GetName(), std::move(file));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ namespace FileSys {
 | 
			
		||||
 | 
			
		||||
class CachedVfsDirectory : public ReadOnlyVfsDirectory {
 | 
			
		||||
public:
 | 
			
		||||
    CachedVfsDirectory(VirtualDir& source_directory);
 | 
			
		||||
    CachedVfsDirectory(VirtualDir&& source_directory);
 | 
			
		||||
 | 
			
		||||
    ~CachedVfsDirectory() override;
 | 
			
		||||
    VirtualFile GetFile(std::string_view file_name) const override;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
 | 
			
		||||
namespace FileSys {
 | 
			
		||||
 | 
			
		||||
ConcatenatedVfsFile::ConcatenatedVfsFile(ConcatenationMap&& concatenation_map_, std::string&& name_)
 | 
			
		||||
ConcatenatedVfsFile::ConcatenatedVfsFile(std::string&& name_, ConcatenationMap&& concatenation_map_)
 | 
			
		||||
    : concatenation_map(std::move(concatenation_map_)), name(std::move(name_)) {
 | 
			
		||||
    DEBUG_ASSERT(this->VerifyContinuity());
 | 
			
		||||
}
 | 
			
		||||
@@ -30,8 +30,8 @@ bool ConcatenatedVfsFile::VerifyContinuity() const {
 | 
			
		||||
 | 
			
		||||
ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;
 | 
			
		||||
 | 
			
		||||
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(const std::vector<VirtualFile>& files,
 | 
			
		||||
                                                      std::string&& name) {
 | 
			
		||||
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::string&& name,
 | 
			
		||||
                                                      std::vector<VirtualFile>&& files) {
 | 
			
		||||
    // Fold trivial cases.
 | 
			
		||||
    if (files.empty()) {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
@@ -46,20 +46,21 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(const std::vector<VirtualF
 | 
			
		||||
    u64 last_offset = 0;
 | 
			
		||||
 | 
			
		||||
    for (auto& file : files) {
 | 
			
		||||
        const auto size = file->GetSize();
 | 
			
		||||
 | 
			
		||||
        concatenation_map.emplace_back(ConcatenationEntry{
 | 
			
		||||
            .offset = last_offset,
 | 
			
		||||
            .file = file,
 | 
			
		||||
            .file = std::move(file),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        last_offset += file->GetSize();
 | 
			
		||||
        last_offset += size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return VirtualFile(new ConcatenatedVfsFile(std::move(concatenation_map), std::move(name)));
 | 
			
		||||
    return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
 | 
			
		||||
                                                      const std::multimap<u64, VirtualFile>& files,
 | 
			
		||||
                                                      std::string&& name) {
 | 
			
		||||
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, std::string&& name,
 | 
			
		||||
                                                      std::multimap<u64, VirtualFile>&& files) {
 | 
			
		||||
    // Fold trivial cases.
 | 
			
		||||
    if (files.empty()) {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
@@ -76,6 +77,8 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
 | 
			
		||||
 | 
			
		||||
    // Iteration of a multimap is ordered, so offset will be strictly non-decreasing.
 | 
			
		||||
    for (auto& [offset, file] : files) {
 | 
			
		||||
        const auto size = file->GetSize();
 | 
			
		||||
 | 
			
		||||
        if (offset > last_offset) {
 | 
			
		||||
            concatenation_map.emplace_back(ConcatenationEntry{
 | 
			
		||||
                .offset = last_offset,
 | 
			
		||||
@@ -85,13 +88,13 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
 | 
			
		||||
 | 
			
		||||
        concatenation_map.emplace_back(ConcatenationEntry{
 | 
			
		||||
            .offset = offset,
 | 
			
		||||
            .file = file,
 | 
			
		||||
            .file = std::move(file),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        last_offset = offset + file->GetSize();
 | 
			
		||||
        last_offset = offset + size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return VirtualFile(new ConcatenatedVfsFile(std::move(concatenation_map), std::move(name)));
 | 
			
		||||
    return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string ConcatenatedVfsFile::GetName() const {
 | 
			
		||||
 
 | 
			
		||||
@@ -24,22 +24,20 @@ private:
 | 
			
		||||
    };
 | 
			
		||||
    using ConcatenationMap = std::vector<ConcatenationEntry>;
 | 
			
		||||
 | 
			
		||||
    explicit ConcatenatedVfsFile(std::vector<ConcatenationEntry>&& concatenation_map,
 | 
			
		||||
                                 std::string&& name);
 | 
			
		||||
    explicit ConcatenatedVfsFile(std::string&& name,
 | 
			
		||||
                                 std::vector<ConcatenationEntry>&& concatenation_map);
 | 
			
		||||
    bool VerifyContinuity() const;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    ~ConcatenatedVfsFile() override;
 | 
			
		||||
 | 
			
		||||
    /// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
 | 
			
		||||
    static VirtualFile MakeConcatenatedFile(const std::vector<VirtualFile>& files,
 | 
			
		||||
                                            std::string&& name);
 | 
			
		||||
    static VirtualFile MakeConcatenatedFile(std::string&& name, std::vector<VirtualFile>&& files);
 | 
			
		||||
 | 
			
		||||
    /// Convenience function that turns a map of offsets to files into a concatenated file, filling
 | 
			
		||||
    /// gaps with a given filler byte.
 | 
			
		||||
    static VirtualFile MakeConcatenatedFile(u8 filler_byte,
 | 
			
		||||
                                            const std::multimap<u64, VirtualFile>& files,
 | 
			
		||||
                                            std::string&& name);
 | 
			
		||||
    static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name,
 | 
			
		||||
                                            std::multimap<u64, VirtualFile>&& files);
 | 
			
		||||
 | 
			
		||||
    std::string GetName() const override;
 | 
			
		||||
    std::size_t GetSize() const override;
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ VirtualDir LayeredVfsDirectory::GetDirectoryRelative(std::string_view path) cons
 | 
			
		||||
    for (const auto& layer : dirs) {
 | 
			
		||||
        auto dir = layer->GetDirectoryRelative(path);
 | 
			
		||||
        if (dir != nullptr) {
 | 
			
		||||
            out.push_back(std::move(dir));
 | 
			
		||||
            out.emplace_back(std::move(dir));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -62,11 +62,11 @@ std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
 | 
			
		||||
    std::set<std::string, std::less<>> out_names;
 | 
			
		||||
 | 
			
		||||
    for (const auto& layer : dirs) {
 | 
			
		||||
        for (const auto& file : layer->GetFiles()) {
 | 
			
		||||
        for (auto& file : layer->GetFiles()) {
 | 
			
		||||
            auto file_name = file->GetName();
 | 
			
		||||
            if (!out_names.contains(file_name)) {
 | 
			
		||||
                out_names.emplace(std::move(file_name));
 | 
			
		||||
                out.push_back(file);
 | 
			
		||||
                out.emplace_back(std::move(file));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -86,7 +86,7 @@ std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const {
 | 
			
		||||
    std::vector<VirtualDir> out;
 | 
			
		||||
    out.reserve(names.size());
 | 
			
		||||
    for (const auto& subdir : names)
 | 
			
		||||
        out.push_back(GetSubdirectory(subdir));
 | 
			
		||||
        out.emplace_back(GetSubdirectory(subdir));
 | 
			
		||||
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user