-
Notifications
You must be signed in to change notification settings - Fork 15k
[ADT] Skip DenseMapBase::destroyAll on trivially destructible types #165080
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ADT] Skip DenseMapBase::destroyAll on trivially destructible types #165080
Conversation
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.
|
@llvm/pr-subscribers-llvm-adt Author: Kazu Hirata (kazutakahirata) ChangesDenseMap::destroyAll currently iterates through the entire bucket This patch introduces "constexpr if" at the beginning of destroyAll to Full diff: https://github.com/llvm/llvm-project/pull/165080.diff 2 Files Affected:
diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index 25b5262800a10..3d91defe2f98d 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -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;
diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp
index 50e9c6e138ef1..aceb4f30d878d 100644
--- a/llvm/unittests/ADT/DenseMapTest.cpp
+++ b/llvm/unittests/ADT/DenseMapTest.cpp
@@ -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;
@@ -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
|
…lvm#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.
…lvm#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.
…lvm#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.
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.