Files
clice/include/Index/MergedIndex.h
2025-10-05 22:46:32 +08:00

139 lines
3.7 KiB
C++

#pragma once
#include "TUIndex.h"
#define ROARING_EXCEPTIONS 0
#define ROARING_TERMINATE(message) std::abort()
#include "roaring/roaring.hh"
#include "llvm/Support/Allocator.h"
namespace clice::index {
/// struct CompilationContext {
/// /// The target of this compilation.
/// llvm::StringRef target;
///
/// /// The canonical compilation command.
/// llvm::StringRef command;
///
/// /// A version field for verification.
/// std::uint32_t version;
/// };
///
/// struct HeaderContext : CompilationContext {
/// /// The include location in the include graph.
/// std::uint32_t include;
///
/// /// The path of the file includes this header.
/// llvm::StringRef path;
/// };
struct HeaderContexts {
std::uint32_t version = 0;
using Context = std::pair<std::uint32_t, std::uint32_t>;
/// A array of include location and its context id.
llvm::SmallVector<Context> includes;
};
struct MergedIndex {
/// For each merged index, we will give it a canonical id.
/// The max canonical id.
std::uint32_t max_canonical_id = 0;
/// We use the value of SHA256 to judge whether two indices are same.
/// Index with same content will be given same canonical id.
llvm::DenseMap<llvm::StringRef, std::uint32_t> canonical_cache;
/// The allocator for storing sha256 hash.
llvm::BumpPtrAllocator allocator;
/// The reference count of each canonical id.
std::vector<std::uint32_t> canonical_ref_counts;
/// The canonical id set of removed index.
roaring::Roaring removed;
/// A map between source file path and its header contexts.
llvm::StringMap<HeaderContexts> contexts;
/// All merged symbol relations.
llvm::DenseMap<SymbolHash, llvm::DenseMap<Relation, roaring::Roaring>> relations;
/// All merged symbol occurrences.
llvm::DenseMap<Occurrence, roaring::Roaring> occurrences;
void remove(llvm::StringRef path);
void merge(llvm::StringRef path, std::uint32_t include, FileIndex& index);
};
} // namespace clice::index
namespace llvm {
template <typename... Ts>
unsigned dense_hash(const Ts&... ts) {
return llvm::DenseMapInfo<std::tuple<Ts...>>::getHashValue(std::tuple{ts...});
}
template <>
struct DenseMapInfo<clice::index::Occurrence> {
using R = clice::LocalSourceRange;
using V = clice::index::Occurrence;
inline static V getEmptyKey() {
return V(R(-1, 0), 0);
}
inline static V getTombstoneKey() {
return V(R(-2, 0), 0);
}
static auto getHashValue(const V& v) {
return dense_hash(v.range.begin, v.range.end, v.target);
}
static bool isEqual(const V& lhs, const V& rhs) {
return lhs.range == rhs.range && lhs.target == rhs.target;
}
};
template <>
struct DenseMapInfo<clice::index::Relation> {
using R = clice::index::Relation;
inline static R getEmptyKey() {
return R{
.kind = clice::RelationKind(),
.range = clice::LocalSourceRange(-1, 0),
.target_symbol = 0,
};
}
inline static R getTombstoneKey() {
return R{
.kind = clice::RelationKind(),
.range = clice::LocalSourceRange(-2, 0),
.target_symbol = 0,
};
}
/// Contextual doen't take part in hashing and equality.
static auto getHashValue(const R& relation) {
return dense_hash(relation.kind.value(),
relation.range.begin,
relation.range.end,
relation.target_symbol);
}
static bool isEqual(const R& lhs, const R& rhs) {
return lhs.kind == rhs.kind && lhs.range == rhs.range &&
lhs.target_symbol == rhs.target_symbol;
}
};
} // namespace llvm