#ifndef LLVM_ADT_DENSEMAP_H
#define LLVM_ADT_DENSEMAP_H
-#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/EpochTracker.h"
#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include "llvm/Support/type_traits.h"
-#include "llvm/ADT/DenseMapInfo.h"
#include <algorithm>
-#include <iterator>
-#include <new>
-#include <utility>
#include <cassert>
#include <climits>
#include <cstddef>
#include <cstring>
+#include <iterator>
+#include <new>
+#include <utility>
namespace llvm {
-template<typename KeyT, typename ValueT,
- typename KeyInfoT = DenseMapInfo<KeyT>,
- bool IsConst = false>
-class DenseMapIterator;
+namespace detail {
+// We extend a pair to allow users to override the bucket type with their own
+// implementation without requiring two members.
+template <typename KeyT, typename ValueT>
+struct DenseMapPair : public std::pair<KeyT, ValueT> {
+ KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
+ const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
+ ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
+ const ValueT &getSecond() const { return std::pair<KeyT, ValueT>::second; }
+};
+}
-template<typename DerivedT,
- typename KeyT, typename ValueT, typename KeyInfoT>
-class DenseMapBase {
-protected:
- typedef std::pair<KeyT, ValueT> BucketT;
+template <
+ typename KeyT, typename ValueT, typename KeyInfoT = DenseMapInfo<KeyT>,
+ typename Bucket = detail::DenseMapPair<KeyT, ValueT>, bool IsConst = false>
+class DenseMapIterator;
+template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
+ typename BucketT>
+class DenseMapBase : public DebugEpochBase {
public:
+ typedef unsigned size_type;
typedef KeyT key_type;
typedef ValueT mapped_type;
typedef BucketT value_type;
- typedef DenseMapIterator<KeyT, ValueT, KeyInfoT> iterator;
- typedef DenseMapIterator<KeyT, ValueT,
- KeyInfoT, true> const_iterator;
+ typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT> iterator;
+ typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT, true>
+ const_iterator;
inline iterator begin() {
// When the map is empty, avoid the overhead of AdvancePastEmptyBuckets().
- return empty() ? end() : iterator(getBuckets(), getBucketsEnd());
+ return empty() ? end() : iterator(getBuckets(), getBucketsEnd(), *this);
}
inline iterator end() {
- return iterator(getBucketsEnd(), getBucketsEnd(), true);
+ return iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
}
inline const_iterator begin() const {
- return empty() ? end() : const_iterator(getBuckets(), getBucketsEnd());
+ return empty() ? end()
+ : const_iterator(getBuckets(), getBucketsEnd(), *this);
}
inline const_iterator end() const {
- return const_iterator(getBucketsEnd(), getBucketsEnd(), true);
+ return const_iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
}
- bool empty() const { return getNumEntries() == 0; }
+ bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
+ return getNumEntries() == 0;
+ }
unsigned size() const { return getNumEntries(); }
/// Grow the densemap so that it has at least Size buckets. Does not shrink
- void resize(size_t Size) {
+ void resize(size_type Size) {
+ incrementEpoch();
if (Size > getNumBuckets())
grow(Size);
}
void clear() {
+ incrementEpoch();
if (getNumEntries() == 0 && getNumTombstones() == 0) return;
-
+
// If the capacity of the array is huge, and the # elements used is small,
// shrink the array.
if (getNumEntries() * 4 < getNumBuckets() && getNumBuckets() > 64) {
}
const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
+ unsigned NumEntries = getNumEntries();
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
- if (!KeyInfoT::isEqual(P->first, EmptyKey)) {
- if (!KeyInfoT::isEqual(P->first, TombstoneKey)) {
- P->second.~ValueT();
- decrementNumEntries();
+ if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
+ if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
+ P->getSecond().~ValueT();
+ --NumEntries;
}
- P->first = EmptyKey;
+ P->getFirst() = EmptyKey;
}
}
- assert(getNumEntries() == 0 && "Node count imbalance!");
+ assert(NumEntries == 0 && "Node count imbalance!");
+ setNumEntries(0);
setNumTombstones(0);
}
- /// count - Return true if the specified key is in the map.
- bool count(const KeyT &Val) const {
+ /// Return 1 if the specified key is in the map, 0 otherwise.
+ size_type count(const KeyT &Val) const {
const BucketT *TheBucket;
- return LookupBucketFor(Val, TheBucket);
+ return LookupBucketFor(Val, TheBucket) ? 1 : 0;
}
iterator find(const KeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return iterator(TheBucket, getBucketsEnd(), true);
+ return iterator(TheBucket, getBucketsEnd(), *this, true);
return end();
}
const_iterator find(const KeyT &Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return const_iterator(TheBucket, getBucketsEnd(), true);
+ return const_iterator(TheBucket, getBucketsEnd(), *this, true);
return end();
}
iterator find_as(const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return iterator(TheBucket, getBucketsEnd(), true);
+ return iterator(TheBucket, getBucketsEnd(), *this, true);
return end();
}
template<class LookupKeyT>
const_iterator find_as(const LookupKeyT &Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return const_iterator(TheBucket, getBucketsEnd(), true);
+ return const_iterator(TheBucket, getBucketsEnd(), *this, true);
return end();
}
ValueT lookup(const KeyT &Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return TheBucket->second;
+ return TheBucket->getSecond();
return ValueT();
}
std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
BucketT *TheBucket;
if (LookupBucketFor(KV.first, TheBucket))
- return std::make_pair(iterator(TheBucket, getBucketsEnd(), true),
+ return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);
- return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);
+ return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
+ true);
+ }
+
+ // Inserts key,value pair into the map if the key isn't already in the map.
+ // If the key is already in the map, it returns false and doesn't update the
+ // value.
+ std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
+ BucketT *TheBucket;
+ if (LookupBucketFor(KV.first, TheBucket))
+ return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
+ false); // Already in map.
+
+ // Otherwise, insert the new element.
+ TheBucket = InsertIntoBucket(std::move(KV.first),
+ std::move(KV.second),
+ TheBucket);
+ return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
+ true);
}
/// insert - Range insertion of pairs.
if (!LookupBucketFor(Val, TheBucket))
return false; // not in map.
- TheBucket->second.~ValueT();
- TheBucket->first = getTombstoneKey();
+ TheBucket->getSecond().~ValueT();
+ TheBucket->getFirst() = getTombstoneKey();
decrementNumEntries();
incrementNumTombstones();
return true;
}
void erase(iterator I) {
BucketT *TheBucket = &*I;
- TheBucket->second.~ValueT();
- TheBucket->first = getTombstoneKey();
+ TheBucket->getSecond().~ValueT();
+ TheBucket->getFirst() = getTombstoneKey();
decrementNumEntries();
incrementNumTombstones();
}
return FindAndConstruct(Key).second;
}
-#if LLVM_USE_RVALUE_REFERENCES
value_type& FindAndConstruct(KeyT &&Key) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
return *TheBucket;
- return *InsertIntoBucket(Key, ValueT(), TheBucket);
+ return *InsertIntoBucket(std::move(Key), ValueT(), TheBucket);
}
ValueT &operator[](KeyT &&Key) {
- return FindAndConstruct(Key).second;
+ return FindAndConstruct(std::move(Key)).second;
}
-#endif
/// isPointerIntoBucketsArray - Return true if the specified pointer points
/// somewhere into the DenseMap's array of buckets (i.e. either to a key or
const void *getPointerIntoBucketsArray() const { return getBuckets(); }
protected:
- DenseMapBase() {}
+ DenseMapBase() = default;
void destroyAll() {
if (getNumBuckets() == 0) // Nothing to do.
const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
- if (!KeyInfoT::isEqual(P->first, EmptyKey) &&
- !KeyInfoT::isEqual(P->first, TombstoneKey))
- P->second.~ValueT();
- P->first.~KeyT();
+ if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) &&
+ !KeyInfoT::isEqual(P->getFirst(), TombstoneKey))
+ P->getSecond().~ValueT();
+ P->getFirst().~KeyT();
}
-
-#ifndef NDEBUG
- memset((void*)getBuckets(), 0x5a, sizeof(BucketT)*getNumBuckets());
-#endif
}
void initEmpty() {
"# initial buckets must be a power of two!");
const KeyT EmptyKey = getEmptyKey();
for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B)
- new (&B->first) KeyT(EmptyKey);
+ new (&B->getFirst()) KeyT(EmptyKey);
}
void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) {
const KeyT EmptyKey = getEmptyKey();
const KeyT TombstoneKey = getTombstoneKey();
for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) {
- if (!KeyInfoT::isEqual(B->first, EmptyKey) &&
- !KeyInfoT::isEqual(B->first, TombstoneKey)) {
+ if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey) &&
+ !KeyInfoT::isEqual(B->getFirst(), TombstoneKey)) {
// Insert the key/value into the new table.
BucketT *DestBucket;
- bool FoundVal = LookupBucketFor(B->first, DestBucket);
+ bool FoundVal = LookupBucketFor(B->getFirst(), DestBucket);
(void)FoundVal; // silence warning.
assert(!FoundVal && "Key already in new map?");
- DestBucket->first = llvm_move(B->first);
- new (&DestBucket->second) ValueT(llvm_move(B->second));
+ DestBucket->getFirst() = std::move(B->getFirst());
+ new (&DestBucket->getSecond()) ValueT(std::move(B->getSecond()));
incrementNumEntries();
// Free the value.
- B->second.~ValueT();
+ B->getSecond().~ValueT();
}
- B->first.~KeyT();
+ B->getFirst().~KeyT();
}
-
-#ifndef NDEBUG
- if (OldBucketsBegin != OldBucketsEnd)
- memset((void*)OldBucketsBegin, 0x5a,
- sizeof(BucketT) * (OldBucketsEnd - OldBucketsBegin));
-#endif
}
template <typename OtherBaseT>
- void copyFrom(const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT>& other) {
+ void copyFrom(
+ const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT, BucketT> &other) {
+ assert(&other != this);
assert(getNumBuckets() == other.getNumBuckets());
setNumEntries(other.getNumEntries());
getNumBuckets() * sizeof(BucketT));
else
for (size_t i = 0; i < getNumBuckets(); ++i) {
- new (&getBuckets()[i].first) KeyT(other.getBuckets()[i].first);
- if (!KeyInfoT::isEqual(getBuckets()[i].first, getEmptyKey()) &&
- !KeyInfoT::isEqual(getBuckets()[i].first, getTombstoneKey()))
- new (&getBuckets()[i].second) ValueT(other.getBuckets()[i].second);
+ new (&getBuckets()[i].getFirst())
+ KeyT(other.getBuckets()[i].getFirst());
+ if (!KeyInfoT::isEqual(getBuckets()[i].getFirst(), getEmptyKey()) &&
+ !KeyInfoT::isEqual(getBuckets()[i].getFirst(), getTombstoneKey()))
+ new (&getBuckets()[i].getSecond())
+ ValueT(other.getBuckets()[i].getSecond());
}
}
- void swap(DenseMapBase& RHS) {
- std::swap(getNumEntries(), RHS.getNumEntries());
- std::swap(getNumTombstones(), RHS.getNumTombstones());
- }
-
static unsigned getHashValue(const KeyT &Val) {
return KeyInfoT::getHashValue(Val);
}
BucketT *TheBucket) {
TheBucket = InsertIntoBucketImpl(Key, TheBucket);
- TheBucket->first = Key;
- new (&TheBucket->second) ValueT(Value);
+ TheBucket->getFirst() = Key;
+ new (&TheBucket->getSecond()) ValueT(Value);
return TheBucket;
}
-#if LLVM_USE_RVALUE_REFERENCES
BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
BucketT *TheBucket) {
TheBucket = InsertIntoBucketImpl(Key, TheBucket);
- TheBucket->first = Key;
- new (&TheBucket->second) ValueT(std::move(Value));
+ TheBucket->getFirst() = Key;
+ new (&TheBucket->getSecond()) ValueT(std::move(Value));
return TheBucket;
}
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) {
TheBucket = InsertIntoBucketImpl(Key, TheBucket);
- TheBucket->first = std::move(Key);
- new (&TheBucket->second) ValueT(std::move(Value));
+ TheBucket->getFirst() = std::move(Key);
+ new (&TheBucket->getSecond()) ValueT(std::move(Value));
return TheBucket;
}
-#endif
BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) {
+ incrementEpoch();
+
// If the load of the hash table is more than 3/4, or if fewer than 1/8 of
// the buckets are empty (meaning that many are filled with tombstones),
// grow the table.
// causing infinite loops in lookup.
unsigned NewNumEntries = getNumEntries() + 1;
unsigned NumBuckets = getNumBuckets();
- if (NewNumEntries*4 >= NumBuckets*3) {
+ if (LLVM_UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) {
this->grow(NumBuckets * 2);
LookupBucketFor(Key, TheBucket);
NumBuckets = getNumBuckets();
- }
- if (NumBuckets-(NewNumEntries+getNumTombstones()) <= NumBuckets/8) {
+ } else if (LLVM_UNLIKELY(NumBuckets-(NewNumEntries+getNumTombstones()) <=
+ NumBuckets/8)) {
this->grow(NumBuckets);
LookupBucketFor(Key, TheBucket);
}
+ assert(TheBucket);
// Only update the state after we've grown our bucket space appropriately
// so that when growing buckets we have self-consistent entry count.
incrementNumEntries();
// If we are writing over a tombstone, remember this.
- if (!KeyInfoT::isEqual(TheBucket->first, getEmptyKey()))
+ const KeyT EmptyKey = getEmptyKey();
+ if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey))
decrementNumTombstones();
return TheBucket;
const unsigned NumBuckets = getNumBuckets();
if (NumBuckets == 0) {
- FoundBucket = 0;
+ FoundBucket = nullptr;
return false;
}
// FoundTombstone - Keep track of whether we find a tombstone while probing.
- const BucketT *FoundTombstone = 0;
+ const BucketT *FoundTombstone = nullptr;
const KeyT EmptyKey = getEmptyKey();
const KeyT TombstoneKey = getTombstoneKey();
assert(!KeyInfoT::isEqual(Val, EmptyKey) &&
while (1) {
const BucketT *ThisBucket = BucketsPtr + BucketNo;
// Found Val's bucket? If so, return it.
- if (KeyInfoT::isEqual(Val, ThisBucket->first)) {
+ if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
FoundBucket = ThisBucket;
return true;
}
// If we found an empty bucket, the key doesn't exist in the set.
// Insert it and return the default value.
- if (KeyInfoT::isEqual(ThisBucket->first, EmptyKey)) {
+ if (LLVM_LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) {
// If we've already seen a tombstone while probing, fill it in instead
// of the empty bucket we eventually probed to.
- if (FoundTombstone) ThisBucket = FoundTombstone;
FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
return false;
}
// If this is a tombstone, remember it. If Val ends up not in the map, we
// prefer to return it than something that would require more probing.
- if (KeyInfoT::isEqual(ThisBucket->first, TombstoneKey) && !FoundTombstone)
+ if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) &&
+ !FoundTombstone)
FoundTombstone = ThisBucket; // Remember the first tombstone found.
// Otherwise, it's a hash collision or a tombstone, continue quadratic
}
};
-template<typename KeyT, typename ValueT,
- typename KeyInfoT = DenseMapInfo<KeyT> >
-class DenseMap
- : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT>,
- KeyT, ValueT, KeyInfoT> {
+template <typename KeyT, typename ValueT,
+ typename KeyInfoT = DenseMapInfo<KeyT>,
+ typename BucketT = detail::DenseMapPair<KeyT, ValueT>>
+class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
+ KeyT, ValueT, KeyInfoT, BucketT> {
// Lift some types from the dependent base class into this class for
// simplicity of referring to them.
- typedef DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT> BaseT;
- typedef typename BaseT::BucketT BucketT;
- friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT>;
+ typedef DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT> BaseT;
+ friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
BucketT *Buckets;
unsigned NumEntries;
init(NumInitBuckets);
}
- DenseMap(const DenseMap &other) {
+ DenseMap(const DenseMap &other) : BaseT() {
init(0);
copyFrom(other);
}
-#if LLVM_USE_RVALUE_REFERENCES
- DenseMap(DenseMap &&other) {
+ DenseMap(DenseMap &&other) : BaseT() {
init(0);
swap(other);
}
-#endif
template<typename InputIt>
DenseMap(const InputIt &I, const InputIt &E) {
}
void swap(DenseMap& RHS) {
+ this->incrementEpoch();
+ RHS.incrementEpoch();
std::swap(Buckets, RHS.Buckets);
std::swap(NumEntries, RHS.NumEntries);
std::swap(NumTombstones, RHS.NumTombstones);
}
DenseMap& operator=(const DenseMap& other) {
- copyFrom(other);
+ if (&other != this)
+ copyFrom(other);
return *this;
}
-#if LLVM_USE_RVALUE_REFERENCES
DenseMap& operator=(DenseMap &&other) {
this->destroyAll();
operator delete(Buckets);
swap(other);
return *this;
}
-#endif
void copyFrom(const DenseMap& other) {
this->destroyAll();
unsigned OldNumBuckets = NumBuckets;
BucketT *OldBuckets = Buckets;
- allocateBuckets(std::max<unsigned>(64, NextPowerOf2(AtLeast)));
+ allocateBuckets(std::max<unsigned>(64, static_cast<unsigned>(NextPowerOf2(AtLeast-1))));
assert(Buckets);
if (!OldBuckets) {
this->BaseT::initEmpty();
this->destroyAll();
// Reduce the number of buckets.
- unsigned NewNumBuckets
- = std::max(64, 1 << (Log2_32_Ceil(OldNumEntries) + 1));
+ unsigned NewNumBuckets = 0;
+ if (OldNumEntries)
+ NewNumBuckets = std::max(64, 1 << (Log2_32_Ceil(OldNumEntries) + 1));
if (NewNumBuckets == NumBuckets) {
this->BaseT::initEmpty();
return;
bool allocateBuckets(unsigned Num) {
NumBuckets = Num;
if (NumBuckets == 0) {
- Buckets = 0;
+ Buckets = nullptr;
return false;
}
}
};
-template<typename KeyT, typename ValueT,
- unsigned InlineBuckets = 4,
- typename KeyInfoT = DenseMapInfo<KeyT> >
+template <typename KeyT, typename ValueT, unsigned InlineBuckets = 4,
+ typename KeyInfoT = DenseMapInfo<KeyT>,
+ typename BucketT = detail::DenseMapPair<KeyT, ValueT>>
class SmallDenseMap
- : public DenseMapBase<SmallDenseMap<KeyT, ValueT, InlineBuckets, KeyInfoT>,
- KeyT, ValueT, KeyInfoT> {
+ : public DenseMapBase<
+ SmallDenseMap<KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT>, KeyT,
+ ValueT, KeyInfoT, BucketT> {
// Lift some types from the dependent base class into this class for
// simplicity of referring to them.
- typedef DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT> BaseT;
- typedef typename BaseT::BucketT BucketT;
- friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT>;
+ typedef DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT> BaseT;
+ friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
unsigned Small : 1;
unsigned NumEntries : 31;
/// A "union" of an inline bucket array and the struct representing
/// a large bucket. This union will be discriminated by the 'Small' bit.
- typename AlignedCharArray<BucketT[InlineBuckets], LargeRep>::union_type
- storage;
+ AlignedCharArrayUnion<BucketT[InlineBuckets], LargeRep> storage;
public:
explicit SmallDenseMap(unsigned NumInitBuckets = 0) {
init(NumInitBuckets);
}
- SmallDenseMap(const SmallDenseMap &other) {
+ SmallDenseMap(const SmallDenseMap &other) : BaseT() {
init(0);
copyFrom(other);
}
-#if LLVM_USE_RVALUE_REFERENCES
- SmallDenseMap(SmallDenseMap &&other) {
+ SmallDenseMap(SmallDenseMap &&other) : BaseT() {
init(0);
swap(other);
}
-#endif
template<typename InputIt>
SmallDenseMap(const InputIt &I, const InputIt &E) {
for (unsigned i = 0, e = InlineBuckets; i != e; ++i) {
BucketT *LHSB = &getInlineBuckets()[i],
*RHSB = &RHS.getInlineBuckets()[i];
- bool hasLHSValue = (!KeyInfoT::isEqual(LHSB->first, EmptyKey) &&
- !KeyInfoT::isEqual(LHSB->first, TombstoneKey));
- bool hasRHSValue = (!KeyInfoT::isEqual(RHSB->first, EmptyKey) &&
- !KeyInfoT::isEqual(RHSB->first, TombstoneKey));
+ bool hasLHSValue = (!KeyInfoT::isEqual(LHSB->getFirst(), EmptyKey) &&
+ !KeyInfoT::isEqual(LHSB->getFirst(), TombstoneKey));
+ bool hasRHSValue = (!KeyInfoT::isEqual(RHSB->getFirst(), EmptyKey) &&
+ !KeyInfoT::isEqual(RHSB->getFirst(), TombstoneKey));
if (hasLHSValue && hasRHSValue) {
// Swap together if we can...
std::swap(*LHSB, *RHSB);
continue;
}
// Swap separately and handle any assymetry.
- std::swap(LHSB->first, RHSB->first);
+ std::swap(LHSB->getFirst(), RHSB->getFirst());
if (hasLHSValue) {
- new (&RHSB->second) ValueT(llvm_move(LHSB->second));
- LHSB->second.~ValueT();
+ new (&RHSB->getSecond()) ValueT(std::move(LHSB->getSecond()));
+ LHSB->getSecond().~ValueT();
} else if (hasRHSValue) {
- new (&LHSB->second) ValueT(llvm_move(RHSB->second));
- RHSB->second.~ValueT();
+ new (&LHSB->getSecond()) ValueT(std::move(RHSB->getSecond()));
+ RHSB->getSecond().~ValueT();
}
}
return;
SmallDenseMap &LargeSide = Small ? RHS : *this;
// First stash the large side's rep and move the small side across.
- LargeRep TmpRep = llvm_move(*LargeSide.getLargeRep());
+ LargeRep TmpRep = std::move(*LargeSide.getLargeRep());
LargeSide.getLargeRep()->~LargeRep();
LargeSide.Small = true;
// This is similar to the standard move-from-old-buckets, but the bucket
for (unsigned i = 0, e = InlineBuckets; i != e; ++i) {
BucketT *NewB = &LargeSide.getInlineBuckets()[i],
*OldB = &SmallSide.getInlineBuckets()[i];
- new (&NewB->first) KeyT(llvm_move(OldB->first));
- OldB->first.~KeyT();
- if (!KeyInfoT::isEqual(NewB->first, EmptyKey) &&
- !KeyInfoT::isEqual(NewB->first, TombstoneKey)) {
- new (&NewB->second) ValueT(llvm_move(OldB->second));
- OldB->second.~ValueT();
+ new (&NewB->getFirst()) KeyT(std::move(OldB->getFirst()));
+ OldB->getFirst().~KeyT();
+ if (!KeyInfoT::isEqual(NewB->getFirst(), EmptyKey) &&
+ !KeyInfoT::isEqual(NewB->getFirst(), TombstoneKey)) {
+ new (&NewB->getSecond()) ValueT(std::move(OldB->getSecond()));
+ OldB->getSecond().~ValueT();
}
}
// The hard part of moving the small buckets across is done, just move
// the TmpRep into its new home.
SmallSide.Small = false;
- new (SmallSide.getLargeRep()) LargeRep(llvm_move(TmpRep));
+ new (SmallSide.getLargeRep()) LargeRep(std::move(TmpRep));
}
SmallDenseMap& operator=(const SmallDenseMap& other) {
- copyFrom(other);
+ if (&other != this)
+ copyFrom(other);
return *this;
}
-#if LLVM_USE_RVALUE_REFERENCES
SmallDenseMap& operator=(SmallDenseMap &&other) {
this->destroyAll();
deallocateBuckets();
swap(other);
return *this;
}
-#endif
void copyFrom(const SmallDenseMap& other) {
this->destroyAll();
Small = true;
if (other.getNumBuckets() > InlineBuckets) {
Small = false;
- allocateBuckets(other.getNumBuckets());
+ new (getLargeRep()) LargeRep(allocateBuckets(other.getNumBuckets()));
}
this->BaseT::copyFrom(other);
}
}
void grow(unsigned AtLeast) {
- if (AtLeast > InlineBuckets)
- AtLeast = std::max<unsigned>(64, NextPowerOf2(AtLeast));
+ if (AtLeast >= InlineBuckets)
+ AtLeast = std::max<unsigned>(64, NextPowerOf2(AtLeast-1));
if (Small) {
- if (AtLeast <= InlineBuckets)
+ if (AtLeast < InlineBuckets)
return; // Nothing to do.
// First move the inline buckets into a temporary storage.
- typename AlignedCharArray<BucketT[InlineBuckets]>::union_type
- TmpStorage;
+ AlignedCharArrayUnion<BucketT[InlineBuckets]> TmpStorage;
BucketT *TmpBegin = reinterpret_cast<BucketT *>(TmpStorage.buffer);
BucketT *TmpEnd = TmpBegin;
const KeyT EmptyKey = this->getEmptyKey();
const KeyT TombstoneKey = this->getTombstoneKey();
for (BucketT *P = getBuckets(), *E = P + InlineBuckets; P != E; ++P) {
- if (!KeyInfoT::isEqual(P->first, EmptyKey) &&
- !KeyInfoT::isEqual(P->first, TombstoneKey)) {
+ if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) &&
+ !KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
assert(size_t(TmpEnd - TmpBegin) < InlineBuckets &&
"Too many inline buckets!");
- new (&TmpEnd->first) KeyT(llvm_move(P->first));
- new (&TmpEnd->second) ValueT(llvm_move(P->second));
+ new (&TmpEnd->getFirst()) KeyT(std::move(P->getFirst()));
+ new (&TmpEnd->getSecond()) ValueT(std::move(P->getSecond()));
++TmpEnd;
- P->second.~ValueT();
+ P->getSecond().~ValueT();
}
- P->first.~KeyT();
+ P->getFirst().~KeyT();
}
// Now make this map use the large rep, and move all the entries back
return;
}
- LargeRep OldRep = llvm_move(*getLargeRep());
+ LargeRep OldRep = std::move(*getLargeRep());
getLargeRep()->~LargeRep();
if (AtLeast <= InlineBuckets) {
Small = true;
}
};
-template<typename KeyT, typename ValueT,
- typename KeyInfoT, bool IsConst>
-class DenseMapIterator {
- typedef std::pair<KeyT, ValueT> Bucket;
- typedef DenseMapIterator<KeyT, ValueT,
- KeyInfoT, true> ConstIterator;
- friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, true>;
+template <typename KeyT, typename ValueT, typename KeyInfoT, typename Bucket,
+ bool IsConst>
+class DenseMapIterator : DebugEpochBase::HandleBase {
+ typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true> ConstIterator;
+ friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
+ friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
+
public:
typedef ptrdiff_t difference_type;
- typedef typename conditional<IsConst, const Bucket, Bucket>::type value_type;
+ typedef typename std::conditional<IsConst, const Bucket, Bucket>::type
+ value_type;
typedef value_type *pointer;
typedef value_type &reference;
typedef std::forward_iterator_tag iterator_category;
private:
pointer Ptr, End;
public:
- DenseMapIterator() : Ptr(0), End(0) {}
+ DenseMapIterator() : Ptr(nullptr), End(nullptr) {}
- DenseMapIterator(pointer Pos, pointer E, bool NoAdvance = false)
- : Ptr(Pos), End(E) {
+ DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch,
+ bool NoAdvance = false)
+ : DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) {
+ assert(isHandleInSync() && "invalid construction!");
if (!NoAdvance) AdvancePastEmptyBuckets();
}
- // If IsConst is true this is a converting constructor from iterator to
- // const_iterator and the default copy constructor is used.
- // Otherwise this is a copy constructor for iterator.
- DenseMapIterator(const DenseMapIterator<KeyT, ValueT,
- KeyInfoT, false>& I)
- : Ptr(I.Ptr), End(I.End) {}
+ // Converting ctor from non-const iterators to const iterators. SFINAE'd out
+ // for const iterator destinations so it doesn't end up as a user defined copy
+ // constructor.
+ template <bool IsConstSrc,
+ typename = typename std::enable_if<!IsConstSrc && IsConst>::type>
+ DenseMapIterator(
+ const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I)
+ : DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End) {}
reference operator*() const {
+ assert(isHandleInSync() && "invalid iterator access!");
return *Ptr;
}
pointer operator->() const {
+ assert(isHandleInSync() && "invalid iterator access!");
return Ptr;
}
bool operator==(const ConstIterator &RHS) const {
- return Ptr == RHS.operator->();
+ assert((!Ptr || isHandleInSync()) && "handle not in sync!");
+ assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
+ assert(getEpochAddress() == RHS.getEpochAddress() &&
+ "comparing incomparable iterators!");
+ return Ptr == RHS.Ptr;
}
bool operator!=(const ConstIterator &RHS) const {
- return Ptr != RHS.operator->();
+ assert((!Ptr || isHandleInSync()) && "handle not in sync!");
+ assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
+ assert(getEpochAddress() == RHS.getEpochAddress() &&
+ "comparing incomparable iterators!");
+ return Ptr != RHS.Ptr;
}
inline DenseMapIterator& operator++() { // Preincrement
+ assert(isHandleInSync() && "invalid iterator access!");
++Ptr;
AdvancePastEmptyBuckets();
return *this;
}
DenseMapIterator operator++(int) { // Postincrement
+ assert(isHandleInSync() && "invalid iterator access!");
DenseMapIterator tmp = *this; ++*this; return tmp;
}
const KeyT Empty = KeyInfoT::getEmptyKey();
const KeyT Tombstone = KeyInfoT::getTombstoneKey();
- while (Ptr != End &&
- (KeyInfoT::isEqual(Ptr->first, Empty) ||
- KeyInfoT::isEqual(Ptr->first, Tombstone)))
+ while (Ptr != End && (KeyInfoT::isEqual(Ptr->getFirst(), Empty) ||
+ KeyInfoT::isEqual(Ptr->getFirst(), Tombstone)))
++Ptr;
}
};
-
+
template<typename KeyT, typename ValueT, typename KeyInfoT>
static inline size_t
capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {