Skip to content

Commit d461244

Browse files
[ADT] Skip DenseMapBase::destroyAll on trivially destructible types (#165080)
DenseMap::destroyAll currently iterates through the entire bucket array to call destructors keys and values. We don't need to do that if we know that both key and value types are trivially destructible, meaning that the destructors are no-ops. This patch introduces "constexpr if" at the beginning of destroyAll to skip the rest of the function if both key and value types are trivially destructible.
1 parent 881b001 commit d461244

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

llvm/include/llvm/ADT/DenseMap.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,12 @@ class DenseMapBase : public DebugEpochBase {
353353
DenseMapBase() = default;
354354

355355
void destroyAll() {
356+
// No need to iterate through the buckets if both KeyT and ValueT are
357+
// trivially destructible.
358+
if constexpr (std::is_trivially_destructible_v<KeyT> &&
359+
std::is_trivially_destructible_v<ValueT>)
360+
return;
361+
356362
if (getNumBuckets() == 0) // Nothing to do.
357363
return;
358364

llvm/unittests/ADT/DenseMapTest.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ class CtorTester {
7070

7171
int getValue() const { return Value; }
7272
bool operator==(const CtorTester &RHS) const { return Value == RHS.Value; }
73+
74+
// Return the number of live CtorTester objects, excluding the empty and
75+
// tombstone keys.
76+
static size_t getNumConstructed() {
77+
return std::count_if(Constructed.begin(), Constructed.end(),
78+
[](const CtorTester *Obj) {
79+
int V = Obj->getValue();
80+
return V != -1 && V != -2;
81+
});
82+
}
7383
};
7484

7585
std::set<CtorTester *> CtorTester::Constructed;
@@ -1031,4 +1041,64 @@ TEST(SmallDenseMapCustomTest, InitSize) {
10311041
}
10321042
}
10331043

1044+
TEST(DenseMapCustomTest, KeyDtor) {
1045+
// This test relies on CtorTester being non-trivially destructible.
1046+
static_assert(!std::is_trivially_destructible_v<CtorTester>,
1047+
"CtorTester must not be trivially destructible");
1048+
1049+
// Test that keys are destructed on scope exit.
1050+
EXPECT_EQ(0u, CtorTester::getNumConstructed());
1051+
{
1052+
DenseMap<CtorTester, int, CtorTesterMapInfo> Map;
1053+
Map.try_emplace(CtorTester(0), 1);
1054+
Map.try_emplace(CtorTester(1), 2);
1055+
EXPECT_EQ(2u, CtorTester::getNumConstructed());
1056+
}
1057+
EXPECT_EQ(0u, CtorTester::getNumConstructed());
1058+
1059+
// Test that keys are destructed on erase and shrink_and_clear.
1060+
EXPECT_EQ(0u, CtorTester::getNumConstructed());
1061+
{
1062+
DenseMap<CtorTester, int, CtorTesterMapInfo> Map;
1063+
Map.try_emplace(CtorTester(0), 1);
1064+
Map.try_emplace(CtorTester(1), 2);
1065+
EXPECT_EQ(2u, CtorTester::getNumConstructed());
1066+
Map.erase(CtorTester(1));
1067+
EXPECT_EQ(1u, CtorTester::getNumConstructed());
1068+
Map.shrink_and_clear();
1069+
EXPECT_EQ(0u, CtorTester::getNumConstructed());
1070+
}
1071+
EXPECT_EQ(0u, CtorTester::getNumConstructed());
1072+
}
1073+
1074+
TEST(DenseMapCustomTest, ValueDtor) {
1075+
// This test relies on CtorTester being non-trivially destructible.
1076+
static_assert(!std::is_trivially_destructible_v<CtorTester>,
1077+
"CtorTester must not be trivially destructible");
1078+
1079+
// Test that values are destructed on scope exit.
1080+
EXPECT_EQ(0u, CtorTester::getNumConstructed());
1081+
{
1082+
DenseMap<int, CtorTester> Map;
1083+
Map.try_emplace(0, CtorTester(1));
1084+
Map.try_emplace(1, CtorTester(2));
1085+
EXPECT_EQ(2u, CtorTester::getNumConstructed());
1086+
}
1087+
EXPECT_EQ(0u, CtorTester::getNumConstructed());
1088+
1089+
// Test that values are destructed on erase and shrink_and_clear.
1090+
EXPECT_EQ(0u, CtorTester::getNumConstructed());
1091+
{
1092+
DenseMap<int, CtorTester> Map;
1093+
Map.try_emplace(0, CtorTester(1));
1094+
Map.try_emplace(1, CtorTester(2));
1095+
EXPECT_EQ(2u, CtorTester::getNumConstructed());
1096+
Map.erase(1);
1097+
EXPECT_EQ(1u, CtorTester::getNumConstructed());
1098+
Map.shrink_and_clear();
1099+
EXPECT_EQ(0u, CtorTester::getNumConstructed());
1100+
}
1101+
EXPECT_EQ(0u, CtorTester::getNumConstructed());
1102+
}
1103+
10341104
} // namespace

0 commit comments

Comments
 (0)