diff --git a/include/dwarfs/inode.h b/include/dwarfs/inode.h index 6683e6a6..6bb89886 100644 --- a/include/dwarfs/inode.h +++ b/include/dwarfs/inode.h @@ -51,8 +51,12 @@ class inode : public object { virtual void scan(mmif* mm, inode_options const& options) = 0; virtual void set_num(uint32_t num) = 0; virtual uint32_t num() const = 0; + virtual bool has_category(fragment_category cat) const = 0; virtual uint32_t similarity_hash() const = 0; + virtual uint32_t similarity_hash(fragment_category cat) const = 0; virtual nilsimsa::hash_type const& nilsimsa_similarity_hash() const = 0; + virtual nilsimsa::hash_type const& + nilsimsa_similarity_hash(fragment_category cat) const = 0; virtual size_t size() const = 0; virtual file const* any() const = 0; virtual files_vector const& files() const = 0; diff --git a/src/dwarfs/inode_manager.cpp b/src/dwarfs/inode_manager.cpp index 5df2045d..1e40fc58 100644 --- a/src/dwarfs/inode_manager.cpp +++ b/src/dwarfs/inode_manager.cpp @@ -36,6 +36,7 @@ #include +#include #include #include @@ -120,10 +121,21 @@ class inode_ : public inode { return num_; } + bool has_category(fragment_category cat) const override { + DWARFS_CHECK(!fragments_.empty(), + "has_category() called with no fragments"); + if (fragments_.size() == 1) { + return fragments_.get_single_category() == cat; + } + auto& m = std::get(similarity_); + return m.find(cat) != m.end(); + } + uint32_t similarity_hash() const override { if (files_.empty()) { DWARFS_THROW(runtime_error, "inode has no file (similarity)"); } + // TODO return similarity_hash_; } @@ -131,9 +143,19 @@ class inode_ : public inode { if (files_.empty()) { DWARFS_THROW(runtime_error, "inode has no file (nilsimsa)"); } + // TODO return nilsimsa_similarity_hash_; } + uint32_t similarity_hash(fragment_category cat) const override { + return find_similarity(cat); + } + + nilsimsa::hash_type const& + nilsimsa_similarity_hash(fragment_category cat) const override { + return find_similarity(cat); + } + void set_files(files_vector&& fv) override { if (!files_.empty()) { DWARFS_THROW(runtime_error, "files already set for inode"); @@ -307,6 +329,27 @@ class inode_ : public inode { } private: + template + T const& find_similarity(fragment_category cat) const { + if (fragments_.empty()) [[unlikely]] { + DWARFS_THROW(runtime_error, fmt::format("inode has no fragments ({})", + folly::demangle(typeid(T)))); + } + if (fragments_.size() == 1) { + if (fragments_.get_single_category() != cat) [[unlikely]] { + DWARFS_THROW(runtime_error, fmt::format("category mismatch ({})", + folly::demangle(typeid(T)))); + } + return std::get(similarity_); + } + auto& m = std::get(similarity_); + if (auto it = m.find(cat); it != m.end()) { + return std::get(it->second); + } + DWARFS_THROW(runtime_error, fmt::format("category not found ({})", + folly::demangle(typeid(T)))); + } + template void scan_range(mmif* mm, size_t offset, size_t size, T&& scanner) { static constexpr size_t const chunk_size = 32 << 20;