14 #ifndef LLVM_SUPPORT_ONDISKHASHTABLE_H
15 #define LLVM_SUPPORT_ONDISKHASHTABLE_H
18 #include "llvm/Support/DataTypes.h"
63 typename Info::key_type Key;
66 const typename Info::hash_value_type
Hash;
68 Item(
typename Info::key_type_ref Key,
typename Info::data_type_ref Data,
70 : Key(Key), Data(Data), Next(
nullptr),
Hash(InfoObj.ComputeHash(Key)) {}
74 offset_type NumBuckets;
75 offset_type NumEntries;
89 void insert(Bucket *Buckets,
size_t Size, Item *
E) {
90 Bucket &
B = Buckets[E->Hash & (Size - 1)];
97 void resize(
size_t NewSize) {
98 Bucket *NewBuckets = (Bucket *)std::calloc(NewSize,
sizeof(Bucket));
100 for (
size_t I = 0;
I < NumBuckets; ++
I)
101 for (Item *E = Buckets[
I].Head;
E;) {
104 insert(NewBuckets, NewSize, E);
109 NumBuckets = NewSize;
110 Buckets = NewBuckets;
115 void insert(
typename Info::key_type_ref Key,
116 typename Info::data_type_ref Data) {
118 insert(Key, Data, InfoObj);
124 void insert(
typename Info::key_type_ref Key,
125 typename Info::data_type_ref Data, Info &InfoObj) {
127 if (4 * NumEntries >= 3 * NumBuckets)
128 resize(NumBuckets * 2);
129 insert(Buckets, NumBuckets,
new (BA.
Allocate()) Item(Key, Data, InfoObj));
133 bool contains(
typename Info::key_type_ref Key, Info &InfoObj) {
134 unsigned Hash = InfoObj.ComputeHash(Key);
135 for (Item *
I = Buckets[Hash & (NumBuckets - 1)].Head;
I;
I =
I->Next)
136 if (
I->Hash == Hash && InfoObj.EqualKey(
I->Key, Key))
144 return Emit(Out, InfoObj);
151 using namespace llvm::support;
165 unsigned TargetNumBuckets =
167 if (TargetNumBuckets != NumBuckets)
168 resize(TargetNumBuckets);
171 for (offset_type
I = 0;
I < NumBuckets; ++
I) {
172 Bucket &
B = Buckets[
I];
178 assert(B.Off &&
"Cannot write a bucket at offset 0. Please add padding.");
181 LE.
write<uint16_t>(B.Length);
182 assert(B.Length != 0 &&
"Bucket has a head but zero length?");
185 for (Item *
I = B.Head;
I;
I =
I->Next) {
186 LE.
write<
typename Info::hash_value_type>(
I->Hash);
187 const std::pair<offset_type, offset_type> &Len =
188 InfoObj.EmitKeyDataLength(Out,
I->Key,
I->Data);
190 InfoObj.EmitKey(Out,
I->Key, Len.first);
191 InfoObj.EmitData(Out,
I->Key,
I->Data, Len.second);
195 uint64_t KeyStart = Out.
tell();
196 InfoObj.EmitKey(Out,
I->Key, Len.first);
197 uint64_t DataStart = Out.
tell();
198 InfoObj.EmitData(Out,
I->Key,
I->Data, Len.second);
200 assert(offset_type(DataStart - KeyStart) == Len.first &&
201 "key length does not match bytes written");
202 assert(offset_type(End - DataStart) == Len.second &&
203 "data length does not match bytes written");
209 offset_type TableOff = Out.
tell();
213 LE.
write<uint8_t>(0);
216 LE.
write<offset_type>(NumBuckets);
217 LE.
write<offset_type>(NumEntries);
218 for (offset_type
I = 0;
I < NumBuckets; ++
I)
219 LE.
write<offset_type>(Buckets[
I].Off);
229 Buckets = (Bucket *)std::calloc(NumBuckets,
sizeof(Bucket));
276 const unsigned char *
const Buckets;
277 const unsigned char *
const Base;
289 const unsigned char *Buckets,
290 const unsigned char *Base,
291 const Info &InfoObj = Info())
292 : NumBuckets(NumBuckets), NumEntries(NumEntries), Buckets(Buckets),
293 Base(Base), InfoObj(InfoObj) {
294 assert((reinterpret_cast<uintptr_t>(Buckets) & 0x3) == 0 &&
295 "'buckets' must have a 4-byte alignment");
301 static std::pair<offset_type, offset_type>
303 assert((reinterpret_cast<uintptr_t>(Buckets) & 0x3) == 0 &&
304 "buckets should be 4-byte aligned.");
305 using namespace llvm::support;
307 endian::readNext<offset_type, little, aligned>(Buckets);
309 endian::readNext<offset_type, little, aligned>(Buckets);
310 return std::make_pair(NumBuckets, NumEntries);
315 const unsigned char *
getBase()
const {
return Base; }
318 bool isEmpty()
const {
return NumEntries == 0; }
322 const unsigned char *
const Data;
327 iterator() : Key(), Data(nullptr), Len(0), InfoObj(nullptr) {}
330 : Key(K), Data(D), Len(L), InfoObj(InfoObj) {}
345 return find_hashed(IKey, KeyHash, InfoPtr);
350 Info *InfoPtr =
nullptr) {
351 using namespace llvm::support;
358 const unsigned char *Bucket = Buckets +
sizeof(
offset_type) * Idx;
363 const unsigned char *Items = Base +
Offset;
367 unsigned Len = endian::readNext<uint16_t, little, unaligned>(Items);
369 for (
unsigned i = 0;
i < Len; ++
i) {
372 endian::readNext<hash_value_type, little, unaligned>(Items);
375 const std::pair<offset_type, offset_type> &
L =
376 Info::ReadKeyDataLength(Items);
380 if (ItemHash != KeyHash) {
387 InfoPtr->ReadKey((
const unsigned char *
const)Items, L.first);
390 if (!InfoPtr->EqualKey(X, IKey)) {
396 return iterator(X, Items + L.first, L.second, InfoPtr);
416 const unsigned char *
const Base,
417 const Info &InfoObj = Info()) {
419 auto NumBucketsAndEntries = readNumBucketsAndEntries(Buckets);
421 NumBucketsAndEntries.second,
422 Buckets, Base, InfoObj);
429 template <
typename Info>
431 const unsigned char *Payload;
443 class iterator_base {
444 const unsigned char *
Ptr;
451 iterator_base(
const unsigned char *
const Ptr,
offset_type NumEntries)
452 :
Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries) {}
454 :
Ptr(
nullptr), NumItemsInBucketLeft(0), NumEntriesLeft(0) {}
456 friend bool operator==(
const iterator_base &
X,
const iterator_base &
Y) {
457 return X.NumEntriesLeft == Y.NumEntriesLeft;
459 friend bool operator!=(
const iterator_base &X,
const iterator_base &Y) {
460 return X.NumEntriesLeft != Y.NumEntriesLeft;
465 using namespace llvm::support;
466 if (!NumItemsInBucketLeft) {
469 NumItemsInBucketLeft =
470 endian::readNext<uint16_t, little, unaligned>(
Ptr);
474 const std::pair<offset_type, offset_type> &
L =
475 Info::ReadKeyDataLength(Ptr);
476 Ptr +=
L.first +
L.second;
477 assert(NumItemsInBucketLeft);
478 --NumItemsInBucketLeft;
485 const unsigned char *getItem()
const {
492 const unsigned char *Buckets,
493 const unsigned char *Payload,
494 const unsigned char *Base,
495 const Info &InfoObj = Info())
496 :
base_type(NumBuckets, NumEntries, Buckets, Base, InfoObj),
508 : iterator_base(Ptr, NumEntries), InfoObj(InfoObj) {}
522 auto *LocalPtr = this->getItem();
525 auto L = Info::ReadKeyDataLength(LocalPtr);
528 return InfoObj->ReadKey(LocalPtr,
L.first);
532 return InfoObj->GetExternalKey(getInternalKey());
537 return key_iterator(Payload, this->getNumEntries(), &this->getInfoObj());
554 : iterator_base(Ptr, NumEntries), InfoObj(InfoObj) {}
568 auto *LocalPtr = this->getItem();
571 auto L = Info::ReadKeyDataLength(LocalPtr);
575 return InfoObj->ReadData(Key, LocalPtr +
L.first,
L.second);
580 return data_iterator(Payload, this->getNumEntries(), &this->getInfoObj());
602 Create(
const unsigned char *Buckets,
const unsigned char *
const Payload,
603 const unsigned char *
const Base,
const Info &InfoObj = Info()) {
605 auto NumBucketsAndEntries =
608 NumBucketsAndEntries.first, NumBucketsAndEntries.second,
609 Buckets, Payload, Base, InfoObj);
OnDiskChainedHashTable(offset_type NumBuckets, offset_type NumEntries, const unsigned char *Buckets, const unsigned char *Base, const Info &InfoObj=Info())
offset_type getNumEntries() const
OnDiskChainedHashTable< Info > base_type
static std::pair< offset_type, offset_type > readNumBucketsAndEntries(const unsigned char *&Buckets)
Read the number of buckets and the number of entries from a hash table produced by OnDiskHashTableGen...
internal_key_type getInternalKey() const
const unsigned char * getBase() const
Info::offset_type offset_type
bool operator==(const iterator &X) const
Info::external_key_type external_key_type
Iterates over all of the keys in the table.
offset_type getNumBuckets() const
This file defines the MallocAllocator and BumpPtrAllocator interfaces.
bool operator!=(const iterator &X) const
data_iterator & operator++()
static void advance(T &it, size_t Val)
static GCRegistry::Add< StatepointGC > D("statepoint-example","an example strategy for statepoint")
InstrProfLookupTrait::data_type data_type
InstrProfLookupTrait::offset_type offset_type
OnDiskChainedHashTableGenerator()
uint64_t tell() const
tell - Return the current offset with the file.
data_type operator*() const
Iterates over all the entries in the table, returning the data.
iterator(const internal_key_type K, const unsigned char *D, offset_type L, Info *InfoObj)
offset_type getDataLen() const
base_type::external_key_type external_key_type
data_iterator operator++(int)
static GCRegistry::Add< OcamlGC > B("ocaml","ocaml 3.10-compatible GC")
void insert(typename Info::key_type_ref Key, typename Info::data_type_ref Data)
Insert an entry into the table.
OnDiskIterableChainedHashTable(offset_type NumBuckets, offset_type NumEntries, const unsigned char *Buckets, const unsigned char *Payload, const unsigned char *Base, const Info &InfoObj=Info())
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
static OnDiskIterableChainedHashTable * Create(const unsigned char *Buckets, const unsigned char *const Payload, const unsigned char *const Base, const Info &InfoObj=Info())
Create the hash table.
base_type::offset_type offset_type
void write(ArrayRef< value_type > Vals)
base_type::data_type data_type
data_iterator data_begin()
bool contains(typename Info::key_type_ref Key, Info &InfoObj)
Determine whether an entry has been inserted.
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang","erlang-compatible garbage collector")
static const unsigned End
value_type operator*() const
void insert(typename Info::key_type_ref Key, typename Info::data_type_ref Data, Info &InfoObj)
Insert an entry into the table.
T * Allocate(size_t num=1)
Allocate space for an array of objects without constructing them.
uint64_t NextPowerOf2(uint64_t A)
NextPowerOf2 - Returns the next power of two (in 64-bits) that is strictly greater than A...
key_iterator(const unsigned char *const Ptr, offset_type NumEntries, Info *InfoObj)
iterator_range< data_iterator > data()
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
offset_type Emit(raw_ostream &Out)
Emit the table to Out, which must not be at offset 0.
iterator_range< key_iterator > keys()
external_key_type value_type
Provides lookup on an on disk hash table.
Info::hash_value_type hash_value_type
key_iterator & operator++()
A range adaptor for a pair of iterators.
Info::internal_key_type internal_key_type
key_iterator operator++(int)
base_type::internal_key_type internal_key_type
bool operator!=(uint64_t V1, const APInt &V2)
Generates an on disk hash table.
const unsigned char * getDataPtr() const
Adapter to write values to a stream in a particular byte order.
iterator find(const external_key_type &EKey, Info *InfoPtr=nullptr)
Look up the stored data for a particular key.
offset_type Emit(raw_ostream &Out, Info &InfoObj)
Emit the table to Out, which must not be at offset 0.
data_iterator(const unsigned char *const Ptr, offset_type NumEntries, Info *InfoObj)
value_type operator*() const
static OnDiskChainedHashTable * Create(const unsigned char *Buckets, const unsigned char *const Base, const Info &InfoObj=Info())
Create the hash table.
iterator find_hashed(const internal_key_type &IKey, hash_value_type KeyHash, Info *InfoPtr=nullptr)
Look up the stored data for a particular key with a known hash.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const unsigned char * getBuckets() const
uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align)
Returns the offset to the next integer (mod 2**64) that is greater than or equal to Value and is a mu...
This class implements an extremely fast bulk output stream that can only output to a stream...
std::string Hash(const Unit &U)
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml","ocaml 3.10-compatible collector")
bool operator==(uint64_t V1, const APInt &V2)
base_type::hash_value_type hash_value_type
~OnDiskChainedHashTableGenerator()
Info::data_type data_type
Provides lookup and iteration over an on disk hash table.