mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-10-26 18:20:39 +00:00
Fix a really subtle bug where the entire hash table could fill with
tombstones, causing subsequent insertions to infinitely loop. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@33972 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -28,6 +28,7 @@ struct DenseMapKeyInfo {
|
|||||||
//static bool isPod()
|
//static bool isPod()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Provide DenseMapKeyInfo for all pointers.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct DenseMapKeyInfo<T*> {
|
struct DenseMapKeyInfo<T*> {
|
||||||
static inline T* getEmptyKey() { return (T*)-1; }
|
static inline T* getEmptyKey() { return (T*)-1; }
|
||||||
@@ -51,6 +52,7 @@ class DenseMap {
|
|||||||
BucketT *Buckets;
|
BucketT *Buckets;
|
||||||
|
|
||||||
unsigned NumEntries;
|
unsigned NumEntries;
|
||||||
|
unsigned NumTombstones;
|
||||||
DenseMap(const DenseMap &); // not implemented.
|
DenseMap(const DenseMap &); // not implemented.
|
||||||
public:
|
public:
|
||||||
explicit DenseMap(unsigned NumInitBuckets = 64) {
|
explicit DenseMap(unsigned NumInitBuckets = 64) {
|
||||||
@@ -96,6 +98,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(NumEntries == 0 && "Node count imbalance!");
|
assert(NumEntries == 0 && "Node count imbalance!");
|
||||||
|
NumTombstones = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// count - Return true if the specified key is in the map.
|
/// count - Return true if the specified key is in the map.
|
||||||
@@ -129,6 +132,7 @@ public:
|
|||||||
TheBucket->second.~ValueT();
|
TheBucket->second.~ValueT();
|
||||||
TheBucket->first = getTombstoneKey();
|
TheBucket->first = getTombstoneKey();
|
||||||
--NumEntries;
|
--NumEntries;
|
||||||
|
++NumTombstones;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool erase(iterator I) {
|
bool erase(iterator I) {
|
||||||
@@ -136,6 +140,7 @@ public:
|
|||||||
TheBucket->second.~ValueT();
|
TheBucket->second.~ValueT();
|
||||||
TheBucket->first = getTombstoneKey();
|
TheBucket->first = getTombstoneKey();
|
||||||
--NumEntries;
|
--NumEntries;
|
||||||
|
++NumTombstones;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,12 +155,26 @@ public:
|
|||||||
private:
|
private:
|
||||||
BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
|
BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
|
||||||
BucketT *TheBucket) {
|
BucketT *TheBucket) {
|
||||||
// If the load of the hash table is more than 3/4, grow it.
|
// If the load of the hash table is more than 3/4, or if fewer than 1/8 of
|
||||||
if (NumEntries*4 >= NumBuckets*3) {
|
// the buckets are empty (meaning that many are filled with tombstones),
|
||||||
|
// grow the table.
|
||||||
|
//
|
||||||
|
// The later case is tricky. For example, if we had one empty bucket with
|
||||||
|
// tons of tombstones, failing lookups (e.g. for insertion) would have to
|
||||||
|
// probe almost the entire table until it found the empty bucket. If the
|
||||||
|
// table completely filled with tombstones, no lookup would ever succeed,
|
||||||
|
// causing infinite loops in lookup.
|
||||||
|
if (NumEntries*4 >= NumBuckets*3 ||
|
||||||
|
NumBuckets-(NumEntries+NumTombstones) < NumBuckets/8) {
|
||||||
this->grow();
|
this->grow();
|
||||||
LookupBucketFor(Key, TheBucket);
|
LookupBucketFor(Key, TheBucket);
|
||||||
}
|
}
|
||||||
++NumEntries;
|
++NumEntries;
|
||||||
|
|
||||||
|
// If we are writing over a tombstone, remember this.
|
||||||
|
if (TheBucket->first != getEmptyKey())
|
||||||
|
--NumTombstones;
|
||||||
|
|
||||||
TheBucket->first = Key;
|
TheBucket->first = Key;
|
||||||
new (&TheBucket->second) ValueT(Value);
|
new (&TheBucket->second) ValueT(Value);
|
||||||
return TheBucket;
|
return TheBucket;
|
||||||
@@ -218,6 +237,7 @@ private:
|
|||||||
|
|
||||||
void init(unsigned InitBuckets) {
|
void init(unsigned InitBuckets) {
|
||||||
NumEntries = 0;
|
NumEntries = 0;
|
||||||
|
NumTombstones = 0;
|
||||||
NumBuckets = InitBuckets;
|
NumBuckets = InitBuckets;
|
||||||
assert(InitBuckets && (InitBuckets & InitBuckets-1) == 0 &&
|
assert(InitBuckets && (InitBuckets & InitBuckets-1) == 0 &&
|
||||||
"# initial buckets must be a power of two!");
|
"# initial buckets must be a power of two!");
|
||||||
@@ -234,6 +254,7 @@ private:
|
|||||||
|
|
||||||
// Double the number of buckets.
|
// Double the number of buckets.
|
||||||
NumBuckets <<= 1;
|
NumBuckets <<= 1;
|
||||||
|
NumTombstones = 0;
|
||||||
Buckets = (BucketT*)new char[sizeof(BucketT)*NumBuckets];
|
Buckets = (BucketT*)new char[sizeof(BucketT)*NumBuckets];
|
||||||
|
|
||||||
// Initialize all the keys to EmptyKey.
|
// Initialize all the keys to EmptyKey.
|
||||||
|
|||||||
Reference in New Issue
Block a user