llvm.org GIT mirror llvm / 6446d7e
Add tests for *DenesMap for both key and value types' construction and destruction and fix a bug in SmallDenseMap they caught. This is kind of a poor-man's version of the testing that just adds the addresses to a set on construction and removes them on destruction. We check that double construction and double destruction don't occur. Amusingly enough, this is enough to catch a lot of SmallDenseMap issues because we spend a lot of time with fixed stable addresses in the inline buffer. The SmallDenseMap bug fix included makes grow() not double-destroy in some cases. It also fixes a FIXME there, the code was pretty crappy. We now don't have any wasted initialization, but we do move the entries in inline bucket array an extra time. It's probably a better tradeoff, and is much easier to get correct. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@158639 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 8 years ago
2 changed file(s) with 74 addition(s) and 19 deletion(s). Raw diff Collapse all Expand all
309309 std::swap(getNumTombstones(), RHS.getNumTombstones());
310310 }
311311
312 private:
313312 static unsigned getHashValue(const KeyT &Val) {
314313 return KeyInfoT::getHashValue(Val);
315314 }
324323 return KeyInfoT::getTombstoneKey();
325324 }
326325
326 private:
327327 unsigned getNumEntries() const {
328328 return static_cast(this)->getNumEntries();
329329 }
802802 if (AtLeast <= InlineBuckets)
803803 return; // Nothing to do.
804804
805 // First grow an allocated bucket array in another map and move our
806 // entries into it.
807 // FIXME: This is wasteful, we don't need the inline buffer here, and we
808 // certainly don't need to initialize it to empty.
809 SmallDenseMap TmpMap;
810 TmpMap.Small = false;
811 new (TmpMap.getLargeRep()) LargeRep(allocateBuckets(AtLeast));
812 TmpMap.moveFromOldBuckets(getInlineBuckets(),
813 getInlineBuckets()+InlineBuckets);
814
815 // Now steal the innards back into this map, and arrange for the
816 // temporary map to be cleanly torn down.
817 assert(NumEntries == TmpMap.NumEntries);
805 // First move the inline buckets into a temporary storage.
806 typename AlignedCharArray::union_type
807 TmpStorage;
808 BucketT *TmpBegin = reinterpret_cast(TmpStorage.buffer);
809 BucketT *TmpEnd = TmpBegin;
810
811 // Loop over the buckets, moving non-empty, non-tombstones into the
812 // temporary storage. Have the loop move the TmpEnd forward as it goes.
813 const KeyT EmptyKey = this->getEmptyKey();
814 const KeyT TombstoneKey = this->getTombstoneKey();
815 for (BucketT *P = getBuckets(), *E = P + InlineBuckets; P != E; ++P) {
816 if (!KeyInfoT::isEqual(P->first, EmptyKey) &&
817 !KeyInfoT::isEqual(P->first, TombstoneKey)) {
818 assert((TmpEnd - TmpBegin) < InlineBuckets &&
819 "Too many inline buckets!");
820 new (&TmpEnd->first) KeyT(llvm_move(P->first));
821 new (&TmpEnd->second) ValueT(llvm_move(P->second));
822 ++TmpEnd;
823 P->second.~ValueT();
824 }
825 P->first.~KeyT();
826 }
827
828 // Now make this map use the large rep, and move all the entries back
829 // into it.
818830 Small = false;
819 NumTombstones = llvm_move(TmpMap.NumTombstones);
820 new (getLargeRep()) LargeRep(llvm_move(*TmpMap.getLargeRep()));
821 TmpMap.getLargeRep()->~LargeRep();
822 TmpMap.Small = true;
831 new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
832 this->moveFromOldBuckets(TmpBegin, TmpEnd);
823833 return;
824834 }
825835
99 #include "gtest/gtest.h"
1010 #include "llvm/ADT/DenseMap.h"
1111 #include
12 #include
1213
1314 using namespace llvm;
1415
2728 assert(i < 8192 && "Only support 8192 dummy keys.");
2829 return &dummy_arr1[i];
2930 }
31
32 /// \brief A test class that tries to check that construction and destruction
33 /// occur correctly.
34 class CtorTester {
35 static std::set Constructed;
36 int Value;
37
38 public:
39 explicit CtorTester(int Value = 0) : Value(Value) {
40 EXPECT_TRUE(Constructed.insert(this).second);
41 }
42 CtorTester(uint32_t Value) : Value(Value) {
43 EXPECT_TRUE(Constructed.insert(this).second);
44 }
45 CtorTester(const CtorTester &Arg) : Value(Arg.Value) {
46 EXPECT_TRUE(Constructed.insert(this).second);
47 }
48 ~CtorTester() {
49 EXPECT_EQ(1u, Constructed.erase(this));
50 }
51 operator uint32_t() const { return Value; }
52
53 int getValue() const { return Value; }
54 bool operator==(const CtorTester &RHS) const { return Value == RHS.Value; }
55 };
56
57 std::set CtorTester::Constructed;
58
59 struct CtorTesterMapInfo {
60 static inline CtorTester getEmptyKey() { return CtorTester(-1); }
61 static inline CtorTester getTombstoneKey() { return CtorTester(-2); }
62 static unsigned getHashValue(const CtorTester &Val) {
63 return Val.getValue() * 37u;
64 }
65 static bool isEqual(const CtorTester &LHS, const CtorTester &RHS) {
66 return LHS == RHS;
67 }
68 };
69
70 CtorTester getTestKey(int i, CtorTester *) { return CtorTester(i); }
71 CtorTester getTestValue(int i, CtorTester *) { return CtorTester(42 + i); }
3072
3173 // Test fixture, with helper functions implemented by forwarding to global
3274 // function overloads selected by component types of the type parameter. This
5698 // Register these types for testing.
5799 typedef ::testing::Types,
58100 DenseMap,
101 DenseMap,
59102 SmallDenseMap,
60 SmallDenseMap
103 SmallDenseMap,
104 SmallDenseMap
105 CtorTesterMapInfo>
61106 > DenseMapTestTypes;
62107 TYPED_TEST_CASE(DenseMapTest, DenseMapTestTypes);
63108