From 736884639b2cac0baca1862380368530b773ea3d Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Wed, 7 May 2025 15:44:31 +0100 Subject: [PATCH] [DenseMap] Introduce emplace_or_assign Introduce emplace_or_assign, a variant of insert_or_assign that has slightly better characteristics. --- llvm/include/llvm/ADT/DenseMap.h | 16 +++++++++++++ llvm/unittests/ADT/DenseMapTest.cpp | 35 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h index bb99a41646b08..5f4442c777fad 100644 --- a/llvm/include/llvm/ADT/DenseMap.h +++ b/llvm/include/llvm/ADT/DenseMap.h @@ -324,6 +324,22 @@ class DenseMapBase : public DebugEpochBase { return Ret; } + template + std::pair emplace_or_assign(const KeyT &Key, Ts &&...Args) { + auto Ret = try_emplace(Key, std::forward(Args)...); + if (!Ret.second) + Ret.first->second = ValueT(std::forward(Args)...); + return Ret; + } + + template + std::pair emplace_or_assign(KeyT &&Key, Ts &&...Args) { + auto Ret = try_emplace(std::move(Key), std::forward(Args)...); + if (!Ret.second) + Ret.first->second = ValueT(std::forward(Args)...); + return Ret; + } + bool erase(const KeyT &Val) { BucketT *TheBucket = doFind(Val); if (!TheBucket) diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp index a4c045585fc28..c8a131b4f5f7e 100644 --- a/llvm/unittests/ADT/DenseMapTest.cpp +++ b/llvm/unittests/ADT/DenseMapTest.cpp @@ -545,6 +545,41 @@ TEST(DenseMapCustomTest, InsertOrAssignTest) { EXPECT_EQ(1, CountCopyAndMove::MoveAssignments); } +TEST(DenseMapCustomTest, EmplaceOrAssign) { + DenseMap Map; + + CountCopyAndMove::ResetCounts(); + auto Try0 = Map.emplace_or_assign(3, 3); + EXPECT_TRUE(Try0.second); + EXPECT_EQ(0, CountCopyAndMove::TotalCopies()); + EXPECT_EQ(0, CountCopyAndMove::TotalMoves()); + EXPECT_EQ(1, CountCopyAndMove::ValueConstructions); + + CountCopyAndMove::ResetCounts(); + auto Try1 = Map.emplace_or_assign(3, 4); + EXPECT_FALSE(Try1.second); + EXPECT_EQ(0, CountCopyAndMove::TotalCopies()); + EXPECT_EQ(1, CountCopyAndMove::ValueConstructions); + EXPECT_EQ(0, CountCopyAndMove::MoveConstructions); + EXPECT_EQ(1, CountCopyAndMove::MoveAssignments); + + int Key = 5; + CountCopyAndMove::ResetCounts(); + auto Try2 = Map.emplace_or_assign(Key, 3); + EXPECT_TRUE(Try2.second); + EXPECT_EQ(0, CountCopyAndMove::TotalCopies()); + EXPECT_EQ(0, CountCopyAndMove::TotalMoves()); + EXPECT_EQ(1, CountCopyAndMove::ValueConstructions); + + CountCopyAndMove::ResetCounts(); + auto Try3 = Map.emplace_or_assign(Key, 4); + EXPECT_FALSE(Try3.second); + EXPECT_EQ(0, CountCopyAndMove::TotalCopies()); + EXPECT_EQ(1, CountCopyAndMove::ValueConstructions); + EXPECT_EQ(0, CountCopyAndMove::MoveConstructions); + EXPECT_EQ(1, CountCopyAndMove::MoveAssignments); +} + // Make sure DenseMap works with StringRef keys. TEST(DenseMapCustomTest, StringRefTest) { DenseMap M;