Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions llvm/include/llvm/ADT/DenseMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@ class DenseMapBase : public DebugEpochBase {
DenseMapBase() = default;

void destroyAll() {
// No need to iterate through the buckets if both KeyT and ValueT are
// trivially destructible.
if constexpr (std::is_trivially_destructible_v<KeyT> &&
std::is_trivially_destructible_v<ValueT>)
return;

if (getNumBuckets() == 0) // Nothing to do.
return;

Expand Down
70 changes: 70 additions & 0 deletions llvm/unittests/ADT/DenseMapTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ class CtorTester {

int getValue() const { return Value; }
bool operator==(const CtorTester &RHS) const { return Value == RHS.Value; }

// Return the number of live CtorTester objects, excluding the empty and
// tombstone keys.
static size_t getNumConstructed() {
return std::count_if(Constructed.begin(), Constructed.end(),
[](const CtorTester *Obj) {
int V = Obj->getValue();
return V != -1 && V != -2;
});
}
};

std::set<CtorTester *> CtorTester::Constructed;
Expand Down Expand Up @@ -1031,4 +1041,64 @@ TEST(SmallDenseMapCustomTest, InitSize) {
}
}

TEST(DenseMapCustomTest, KeyDtor) {
// This test relies on CtorTester being non-trivially destructible.
static_assert(!std::is_trivially_destructible_v<CtorTester>,
"CtorTester must not be trivially destructible");

// Test that keys are destructed on scope exit.
EXPECT_EQ(0u, CtorTester::getNumConstructed());
{
DenseMap<CtorTester, int, CtorTesterMapInfo> Map;
Map.try_emplace(CtorTester(0), 1);
Map.try_emplace(CtorTester(1), 2);
EXPECT_EQ(2u, CtorTester::getNumConstructed());
}
EXPECT_EQ(0u, CtorTester::getNumConstructed());

// Test that keys are destructed on erase and shrink_and_clear.
EXPECT_EQ(0u, CtorTester::getNumConstructed());
{
DenseMap<CtorTester, int, CtorTesterMapInfo> Map;
Map.try_emplace(CtorTester(0), 1);
Map.try_emplace(CtorTester(1), 2);
EXPECT_EQ(2u, CtorTester::getNumConstructed());
Map.erase(CtorTester(1));
EXPECT_EQ(1u, CtorTester::getNumConstructed());
Map.shrink_and_clear();
EXPECT_EQ(0u, CtorTester::getNumConstructed());
}
EXPECT_EQ(0u, CtorTester::getNumConstructed());
}

TEST(DenseMapCustomTest, ValueDtor) {
// This test relies on CtorTester being non-trivially destructible.
static_assert(!std::is_trivially_destructible_v<CtorTester>,
"CtorTester must not be trivially destructible");

// Test that values are destructed on scope exit.
EXPECT_EQ(0u, CtorTester::getNumConstructed());
{
DenseMap<int, CtorTester> Map;
Map.try_emplace(0, CtorTester(1));
Map.try_emplace(1, CtorTester(2));
EXPECT_EQ(2u, CtorTester::getNumConstructed());
}
EXPECT_EQ(0u, CtorTester::getNumConstructed());

// Test that values are destructed on erase and shrink_and_clear.
EXPECT_EQ(0u, CtorTester::getNumConstructed());
{
DenseMap<int, CtorTester> Map;
Map.try_emplace(0, CtorTester(1));
Map.try_emplace(1, CtorTester(2));
EXPECT_EQ(2u, CtorTester::getNumConstructed());
Map.erase(1);
EXPECT_EQ(1u, CtorTester::getNumConstructed());
Map.shrink_and_clear();
EXPECT_EQ(0u, CtorTester::getNumConstructed());
}
EXPECT_EQ(0u, CtorTester::getNumConstructed());
}

} // namespace