X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FADT%2FDenseMap.h;h=27f73157a29f38cd39e3fa8c3afab85bec7ff61f;hb=116832190dc04f511dacff847742733cc957d46a;hp=d41061996436282bfe7c6a64903a4e19dc1eac0a;hpb=cef6cfe4a67af030754b4151cd63076c4aab7467;p=oota-llvm.git diff --git a/include/llvm/ADT/DenseMap.h b/include/llvm/ADT/DenseMap.h index d4106199643..27f73157a29 100644 --- a/include/llvm/ADT/DenseMap.h +++ b/include/llvm/ADT/DenseMap.h @@ -15,6 +15,7 @@ #define LLVM_ADT_DENSEMAP_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" @@ -31,49 +32,64 @@ namespace llvm { -template, - 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 +struct DenseMapPair : public std::pair { + KeyT &getFirst() { return std::pair::first; } + const KeyT &getFirst() const { return std::pair::first; } + ValueT &getSecond() { return std::pair::second; } + const ValueT &getSecond() const { return std::pair::second; } +}; +} -template -class DenseMapBase { -protected: - typedef std::pair BucketT; +template < + typename KeyT, typename ValueT, typename KeyInfoT = DenseMapInfo, + typename Bucket = detail::DenseMapPair, bool IsConst = false> +class DenseMapIterator; +template +class DenseMapBase : public DebugEpochBase { public: + typedef unsigned size_type; typedef KeyT key_type; typedef ValueT mapped_type; typedef BucketT value_type; - typedef DenseMapIterator iterator; - typedef DenseMapIterator const_iterator; + typedef DenseMapIterator iterator; + typedef DenseMapIterator + 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, @@ -84,35 +100,37 @@ public: } 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(); } @@ -125,14 +143,14 @@ public: 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 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(); } @@ -141,7 +159,7 @@ public: ValueT lookup(const KeyT &Val) const { const BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) - return TheBucket->second; + return TheBucket->getSecond(); return ValueT(); } @@ -151,32 +169,32 @@ public: std::pair insert(const std::pair &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); } -#if LLVM_HAS_RVALUE_REFERENCES // 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 insert(std::pair &&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(std::move(KV.first), std::move(KV.second), TheBucket); - return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true); + return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), + true); } -#endif - + /// insert - Range insertion of pairs. template void insert(InputIt I, InputIt E) { @@ -190,16 +208,16 @@ public: 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(); } @@ -216,19 +234,17 @@ public: return FindAndConstruct(Key).second; } -#if LLVM_HAS_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 @@ -243,7 +259,7 @@ public: const void *getPointerIntoBucketsArray() const { return getBuckets(); } protected: - DenseMapBase() {} + DenseMapBase() = default; void destroyAll() { if (getNumBuckets() == 0) // Nothing to do. @@ -251,15 +267,11 @@ protected: 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() { @@ -270,7 +282,7 @@ protected: "# 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) { @@ -280,32 +292,28 @@ protected: 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 - void copyFrom(const DenseMapBase& other) { + void copyFrom( + const DenseMapBase &other) { + assert(&other != this); assert(getNumBuckets() == other.getNumBuckets()); setNumEntries(other.getNumEntries()); @@ -316,18 +324,15 @@ protected: 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); } @@ -396,31 +401,31 @@ private: 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_HAS_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. @@ -432,13 +437,13 @@ private: // 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) { - this->grow(NumBuckets * 2); + } else if (LLVM_UNLIKELY(NumBuckets-(NewNumEntries+getNumTombstones()) <= + NumBuckets/8)) { + this->grow(NumBuckets); LookupBucketFor(Key, TheBucket); } assert(TheBucket); @@ -449,7 +454,7 @@ private: // If we are writing over a tombstone, remember this. const KeyT EmptyKey = getEmptyKey(); - if (!KeyInfoT::isEqual(TheBucket->first, EmptyKey)) + if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey)) decrementNumTombstones(); return TheBucket; @@ -466,12 +471,12 @@ private: 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) && @@ -483,14 +488,14 @@ private: 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. FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket; @@ -499,7 +504,8 @@ private: // 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 @@ -528,16 +534,15 @@ public: } }; -template > -class DenseMap - : public DenseMapBase, - KeyT, ValueT, KeyInfoT> { +template , + typename BucketT = detail::DenseMapPair> +class DenseMap : public DenseMapBase, + KeyT, ValueT, KeyInfoT, BucketT> { // Lift some types from the dependent base class into this class for // simplicity of referring to them. - typedef DenseMapBase BaseT; - typedef typename BaseT::BucketT BucketT; - friend class DenseMapBase; + typedef DenseMapBase BaseT; + friend class DenseMapBase; BucketT *Buckets; unsigned NumEntries; @@ -554,12 +559,10 @@ public: copyFrom(other); } -#if LLVM_HAS_RVALUE_REFERENCES DenseMap(DenseMap &&other) : BaseT() { init(0); swap(other); } -#endif template DenseMap(const InputIt &I, const InputIt &E) { @@ -573,6 +576,8 @@ public: } void swap(DenseMap& RHS) { + this->incrementEpoch(); + RHS.incrementEpoch(); std::swap(Buckets, RHS.Buckets); std::swap(NumEntries, RHS.NumEntries); std::swap(NumTombstones, RHS.NumTombstones); @@ -580,11 +585,11 @@ public: } DenseMap& operator=(const DenseMap& other) { - copyFrom(other); + if (&other != this) + copyFrom(other); return *this; } -#if LLVM_HAS_RVALUE_REFERENCES DenseMap& operator=(DenseMap &&other) { this->destroyAll(); operator delete(Buckets); @@ -592,7 +597,6 @@ public: swap(other); return *this; } -#endif void copyFrom(const DenseMap& other) { this->destroyAll(); @@ -618,7 +622,7 @@ public: unsigned OldNumBuckets = NumBuckets; BucketT *OldBuckets = Buckets; - allocateBuckets(std::max(64, NextPowerOf2(AtLeast-1))); + allocateBuckets(std::max(64, static_cast(NextPowerOf2(AtLeast-1)))); assert(Buckets); if (!OldBuckets) { this->BaseT::initEmpty(); @@ -674,7 +678,7 @@ private: bool allocateBuckets(unsigned Num) { NumBuckets = Num; if (NumBuckets == 0) { - Buckets = 0; + Buckets = nullptr; return false; } @@ -683,17 +687,17 @@ private: } }; -template > +template , + typename BucketT = detail::DenseMapPair> class SmallDenseMap - : public DenseMapBase, - KeyT, ValueT, KeyInfoT> { + : public DenseMapBase< + SmallDenseMap, KeyT, + ValueT, KeyInfoT, BucketT> { // Lift some types from the dependent base class into this class for // simplicity of referring to them. - typedef DenseMapBase BaseT; - typedef typename BaseT::BucketT BucketT; - friend class DenseMapBase; + typedef DenseMapBase BaseT; + friend class DenseMapBase; unsigned Small : 1; unsigned NumEntries : 31; @@ -713,17 +717,15 @@ public: init(NumInitBuckets); } - SmallDenseMap(const SmallDenseMap &other) { + SmallDenseMap(const SmallDenseMap &other) : BaseT() { init(0); copyFrom(other); } -#if LLVM_HAS_RVALUE_REFERENCES - SmallDenseMap(SmallDenseMap &&other) { + SmallDenseMap(SmallDenseMap &&other) : BaseT() { init(0); swap(other); } -#endif template SmallDenseMap(const InputIt &I, const InputIt &E) { @@ -752,23 +754,23 @@ public: 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; @@ -783,7 +785,7 @@ public: 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 @@ -793,27 +795,27 @@ public: 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_HAS_RVALUE_REFERENCES SmallDenseMap& operator=(SmallDenseMap &&other) { this->destroyAll(); deallocateBuckets(); @@ -821,7 +823,6 @@ public: swap(other); return *this; } -#endif void copyFrom(const SmallDenseMap& other) { this->destroyAll(); @@ -829,7 +830,7 @@ public: Small = true; if (other.getNumBuckets() > InlineBuckets) { Small = false; - allocateBuckets(other.getNumBuckets()); + new (getLargeRep()) LargeRep(allocateBuckets(other.getNumBuckets())); } this->BaseT::copyFrom(other); } @@ -861,16 +862,16 @@ public: 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 @@ -881,7 +882,7 @@ public: return; } - LargeRep OldRep = llvm_move(*getLargeRep()); + LargeRep OldRep = std::move(*getLargeRep()); getLargeRep()->~LargeRep(); if (AtLeast <= InlineBuckets) { Small = true; @@ -981,56 +982,73 @@ private: } }; -template -class DenseMapIterator { - typedef std::pair Bucket; - typedef DenseMapIterator ConstIterator; - friend class DenseMapIterator; +template +class DenseMapIterator : DebugEpochBase::HandleBase { + typedef DenseMapIterator ConstIterator; + friend class DenseMapIterator; + friend class DenseMapIterator; + public: typedef ptrdiff_t difference_type; - typedef typename conditional::type value_type; + typedef typename std::conditional::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& 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 ::type> + DenseMapIterator( + const DenseMapIterator &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; } @@ -1039,9 +1057,8 @@ private: 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; } };