1 //===--- MemIndex.h - Dynamic in-memory symbol index. -------------- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_MEMINDEX_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_MEMINDEX_H
11 
12 #include "Index.h"
13 #include <mutex>
14 
15 namespace clang {
16 namespace clangd {
17 
18 /// MemIndex is a naive in-memory index suitable for a small set of symbols.
19 class MemIndex : public SymbolIndex {
20 public:
21   MemIndex() = default;
22   // All symbols and refs must outlive this index.
23   template <typename SymbolRange, typename RefRange, typename RelationRange>
MemIndex(SymbolRange && Symbols,RefRange && Refs,RelationRange && Relations)24   MemIndex(SymbolRange &&Symbols, RefRange &&Refs, RelationRange &&Relations) {
25     for (const Symbol &S : Symbols)
26       Index[S.ID] = &S;
27     for (const std::pair<SymbolID, llvm::ArrayRef<Ref>> &R : Refs)
28       this->Refs.try_emplace(R.first, R.second.begin(), R.second.end());
29     for (const Relation &R : Relations)
30       this->Relations[std::make_pair(R.Subject,
31                                      static_cast<uint8_t>(R.Predicate))]
32           .push_back(R.Object);
33   }
34   // Symbols are owned by BackingData, Index takes ownership.
35   template <typename SymbolRange, typename RefRange, typename RelationRange,
36             typename Payload>
MemIndex(SymbolRange && Symbols,RefRange && Refs,RelationRange && Relations,Payload && BackingData,size_t BackingDataSize)37   MemIndex(SymbolRange &&Symbols, RefRange &&Refs, RelationRange &&Relations,
38            Payload &&BackingData, size_t BackingDataSize)
39       : MemIndex(std::forward<SymbolRange>(Symbols),
40                  std::forward<RefRange>(Refs),
41                  std::forward<RelationRange>(Relations)) {
42     KeepAlive = std::shared_ptr<void>(
43         std::make_shared<Payload>(std::move(BackingData)), nullptr);
44     this->BackingDataSize = BackingDataSize;
45   }
46 
47   /// Builds an index from slabs. The index takes ownership of the data.
48   static std::unique_ptr<SymbolIndex> build(SymbolSlab Symbols, RefSlab Refs,
49                                             RelationSlab Relations);
50 
51   bool
52   fuzzyFind(const FuzzyFindRequest &Req,
53             llvm::function_ref<void(const Symbol &)> Callback) const override;
54 
55   void lookup(const LookupRequest &Req,
56               llvm::function_ref<void(const Symbol &)> Callback) const override;
57 
58   bool refs(const RefsRequest &Req,
59             llvm::function_ref<void(const Ref &)> Callback) const override;
60 
61   void relations(const RelationsRequest &Req,
62                  llvm::function_ref<void(const SymbolID &, const Symbol &)>
63                      Callback) const override;
64 
65   size_t estimateMemoryUsage() const override;
66 
67 private:
68   // Index is a set of symbols that are deduplicated by symbol IDs.
69   llvm::DenseMap<SymbolID, const Symbol *> Index;
70   // A map from symbol ID to symbol refs, support query by IDs.
71   llvm::DenseMap<SymbolID, llvm::ArrayRef<Ref>> Refs;
72   // A map from (subject, predicate) pair to objects.
73   static_assert(sizeof(RelationKind) == sizeof(uint8_t),
74                 "RelationKind should be of same size as a uint8_t");
75   llvm::DenseMap<std::pair<SymbolID, uint8_t>, std::vector<SymbolID>> Relations;
76   std::shared_ptr<void> KeepAlive; // poor man's move-only std::any
77   // Size of memory retained by KeepAlive.
78   size_t BackingDataSize = 0;
79 };
80 
81 } // namespace clangd
82 } // namespace clang
83 
84 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_MEMINDEX_H
85