18#ifndef LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H
19#define LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H
21#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/DenseSet.h"
23#include "llvm/ADT/PointerUnion.h"
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/ADT/SmallVector.h"
26#include "llvm/ADT/TinyPtrVector.h"
27#include "llvm/ADT/iterator_range.h"
28#include "llvm/Support/Endian.h"
29#include "llvm/Support/EndianStream.h"
30#include "llvm/Support/OnDiskHashTable.h"
31#include "llvm/Support/raw_ostream.h"
37namespace serialization {
56 template<
typename ReaderInfo,
typename WriterInfo>
61 using HashTable = llvm::OnDiskIterableChainedHashTable<Info>;
66 OnDiskTable(
file_type File,
unsigned NumBuckets,
unsigned NumEntries,
70 Table(NumBuckets, NumEntries, Buckets, Payload,
Base, InfoObj) {}
74 std::vector<file_type> Files;
75 llvm::DenseMap<internal_key_type, data_type>
Data;
78 using Table = llvm::PointerUnion<OnDiskTable *, MergedTable *>;
79 using TableVector = llvm::TinyPtrVector<void *>;
90 llvm::TinyPtrVector<file_type> PendingOverrides;
92 struct AsOnDiskTable {
93 using result_type = OnDiskTable *;
95 result_type operator()(
void *
P)
const {
96 return Table::getFromOpaqueValue(
P).template get<OnDiskTable *>();
100 using table_iterator =
101 llvm::mapped_iterator<TableVector::iterator, AsOnDiskTable>;
102 using table_range = llvm::iterator_range<table_iterator>;
105 table_range tables() {
106 auto Begin = Tables.begin(), End = Tables.end();
107 if (getMergedTable())
109 return llvm::make_range(llvm::map_iterator(
Begin, AsOnDiskTable()),
110 llvm::map_iterator(End, AsOnDiskTable()));
113 MergedTable *getMergedTable()
const {
115 return Tables.empty() ? nullptr : Table::getFromOpaqueValue(*Tables.begin())
116 .template dyn_cast<MergedTable*>();
121 for (
auto *
T : tables())
123 if (
auto *M = getMergedTable())
128 void removeOverriddenTables() {
129 llvm::DenseSet<file_type> Files;
130 Files.insert(PendingOverrides.begin(), PendingOverrides.end());
132 auto ShouldRemove = [&Files](
void *
T) ->
bool {
133 auto *ODT = Table::getFromOpaqueValue(
T).template get<OnDiskTable *>();
134 bool Remove = Files.count(ODT->File);
139 Tables.erase(std::remove_if(tables().begin().getCurrent(), Tables.end(),
142 PendingOverrides.clear();
146 MergedTable *Merged = getMergedTable();
148 Merged =
new MergedTable;
152 for (
auto *ODT : tables()) {
153 auto &HT = ODT->Table;
154 Info &InfoObj = HT.getInfoObj();
156 for (
auto I = HT.data_begin(),
E = HT.data_end(); I !=
E; ++I) {
157 auto *LocalPtr = I.getItem();
160 auto L = InfoObj.ReadKeyDataLength(LocalPtr);
163 InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second,
167 Merged->Files.push_back(ODT->File);
172 Tables.push_back(Table(Merged).getOpaqueValue());
179 : Tables(
std::move(O.Tables)),
180 PendingOverrides(
std::move(O.PendingOverrides)) {
188 Tables = std::move(O.Tables);
190 PendingOverrides = std::move(O.PendingOverrides);
198 using namespace llvm::support;
202 uint32_t BucketOffset =
203 endian::readNext<uint32_t, llvm::endianness::little>(Ptr);
207 endian::readNext<uint32_t, llvm::endianness::little>(Ptr);
211 OverriddenFiles.reserve(NumFiles);
212 for (; NumFiles != 0; --NumFiles)
213 OverriddenFiles.push_back(InfoObj.ReadFileRef(Ptr));
214 PendingOverrides.insert(PendingOverrides.end(), OverriddenFiles.begin(),
215 OverriddenFiles.end());
219 auto NumBucketsAndEntries =
220 OnDiskTable::HashTable::readNumBucketsAndEntries(Buckets);
223 Table NewTable =
new OnDiskTable(
File, NumBucketsAndEntries.first,
224 NumBucketsAndEntries.second,
225 Buckets, Ptr,
Data, std::move(InfoObj));
226 Tables.push_back(NewTable.getOpaqueValue());
233 if (!PendingOverrides.empty())
234 removeOverriddenTables();
236 if (Tables.size() >
static_cast<unsigned>(Info::MaxTables))
240 auto KeyHash = Info::ComputeHash(Key);
242 if (MergedTable *M = getMergedTable()) {
243 auto It = M->Data.find(Key);
244 if (It != M->Data.end())
250 for (
auto *ODT : tables()) {
251 auto &HT = ODT->Table;
252 auto It = HT.find_hashed(Key, KeyHash);
254 HT.getInfoObj().ReadDataInto(Key, It.getDataPtr(), It.getDataLen(),
267 if (!PendingOverrides.empty())
268 removeOverriddenTables();
270 if (MergedTable *M = getMergedTable()) {
271 for (
auto &KV : M->Data)
272 Info::MergeDataInto(KV.second, ResultBuilder);
275 for (
auto *ODT : tables()) {
276 auto &HT = ODT->Table;
277 Info &InfoObj = HT.getInfoObj();
278 for (
auto I = HT.data_begin(),
E = HT.data_end(); I !=
E; ++I) {
279 auto *LocalPtr = I.getItem();
282 auto L = InfoObj.ReadKeyDataLength(LocalPtr);
284 InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second, ResultBuilder);
293template<
typename ReaderInfo,
typename WriterInfo>
296 using Generator = llvm::OnDiskChainedHashTableGenerator<WriterInfo>;
303 void insert(
typename WriterInfo::key_type_ref Key,
304 typename WriterInfo::data_type_ref
Data, WriterInfo &Info) {
305 Gen.insert(Key,
Data, Info);
310 using namespace llvm::support;
312 llvm::raw_svector_ostream OutStream(Out);
316 endian::Writer Writer(OutStream, llvm::endianness::little);
319 Writer.write<uint32_t>(0);
321 if (
auto *Merged =
Base ?
Base->getMergedTable() :
nullptr) {
323 Writer.write<uint32_t>(Merged->Files.size());
324 for (
const auto &F : Merged->Files)
325 Info.EmitFileRef(OutStream, F);
328 for (
auto &KV : Merged->Data) {
329 if (!Gen.contains(KV.first, Info))
330 Gen.insert(KV.first, Info.ImportData(KV.second), Info);
333 Writer.write<uint32_t>(0);
338 uint32_t BucketOffset = Gen.Emit(OutStream, Info);
341 endian::write32le(Out.data(), BucketOffset);
Writer for the on-disk hash table.
MultiOnDiskHashTableGenerator()
void insert(typename WriterInfo::key_type_ref Key, typename WriterInfo::data_type_ref Data, WriterInfo &Info)
void emit(llvm::SmallVectorImpl< char > &Out, WriterInfo &Info, const BaseTable *Base)
A collection of on-disk hash tables, merged when relevant for performance.
data_type find(const external_key_type &EKey)
Find and read the lookup results for EKey.
typename Info::file_type file_type
A handle to a file, used when overriding tables.
MultiOnDiskHashTable(MultiOnDiskHashTable &&O)
MultiOnDiskHashTable()=default
typename Info::external_key_type external_key_type
typename Info::data_type data_type
typename Info::internal_key_type internal_key_type
const unsigned char * storage_type
A pointer to an on-disk representation of the hash table.
MultiOnDiskHashTable & operator=(MultiOnDiskHashTable &&O)
typename Info::data_type_builder data_type_builder
data_type findAll()
Read all the lookup results into a single value.
void add(file_type File, storage_type Data, Info InfoObj=Info())
Add the table Data loaded from file File.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
const FunctionProtoType * T