mirror of
https://github.com/RPCSX/llvm.git
synced 2025-01-19 19:03:50 +00:00
[DenseMap] Add a C++17-style try_emplace method.
This provides an elegant pattern to solve the "construct if not in map already" problem we have many times in LLVM. Without try_emplace we either have to rely on a sentinel value (nullptr) or do two lookups. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@276277 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b11b3529ce
commit
1a324fd49a
@ -169,30 +169,45 @@ public:
|
|||||||
// If the key is already in the map, it returns false and doesn't update the
|
// If the key is already in the map, it returns false and doesn't update the
|
||||||
// value.
|
// value.
|
||||||
std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
|
std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
|
||||||
BucketT *TheBucket;
|
return try_emplace(KV.first, KV.second);
|
||||||
if (LookupBucketFor(KV.first, TheBucket))
|
|
||||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
|
||||||
false); // Already in map.
|
|
||||||
|
|
||||||
// Otherwise, insert the new element.
|
|
||||||
TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);
|
|
||||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserts key,value pair into the map if the key isn't already in the map.
|
// Inserts key,value pair into the map if the key isn't already in the map.
|
||||||
// If the key is already in the map, it returns false and doesn't update the
|
// If the key is already in the map, it returns false and doesn't update the
|
||||||
// value.
|
// value.
|
||||||
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
|
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
|
||||||
|
return try_emplace(std::move(KV.first), std::move(KV.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inserts key,value pair into the map if the key isn't already in the map.
|
||||||
|
// The value is constructed in-place if the key is not in the map, otherwise
|
||||||
|
// it is not moved.
|
||||||
|
template <typename... Ts>
|
||||||
|
std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
|
||||||
BucketT *TheBucket;
|
BucketT *TheBucket;
|
||||||
if (LookupBucketFor(KV.first, TheBucket))
|
if (LookupBucketFor(Key, TheBucket))
|
||||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||||
false); // Already in map.
|
false); // Already in map.
|
||||||
|
|
||||||
// Otherwise, insert the new element.
|
// Otherwise, insert the new element.
|
||||||
TheBucket = InsertIntoBucket(std::move(KV.first),
|
TheBucket =
|
||||||
std::move(KV.second),
|
InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
|
||||||
TheBucket);
|
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inserts key,value pair into the map if the key isn't already in the map.
|
||||||
|
// The value is constructed in-place if the key is not in the map, otherwise
|
||||||
|
// it is not moved.
|
||||||
|
template <typename... Ts>
|
||||||
|
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
|
||||||
|
BucketT *TheBucket;
|
||||||
|
if (LookupBucketFor(Key, TheBucket))
|
||||||
|
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||||
|
false); // Already in map.
|
||||||
|
|
||||||
|
// Otherwise, insert the new element.
|
||||||
|
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
|
||||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
@ -211,8 +226,8 @@ public:
|
|||||||
false); // Already in map.
|
false); // Already in map.
|
||||||
|
|
||||||
// Otherwise, insert the new element.
|
// Otherwise, insert the new element.
|
||||||
TheBucket = InsertIntoBucket(std::move(KV.first), std::move(KV.second), Val,
|
TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
|
||||||
TheBucket);
|
std::move(KV.second), Val);
|
||||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
@ -249,7 +264,7 @@ public:
|
|||||||
if (LookupBucketFor(Key, TheBucket))
|
if (LookupBucketFor(Key, TheBucket))
|
||||||
return *TheBucket;
|
return *TheBucket;
|
||||||
|
|
||||||
return *InsertIntoBucket(Key, ValueT(), TheBucket);
|
return *InsertIntoBucket(TheBucket, Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueT &operator[](const KeyT &Key) {
|
ValueT &operator[](const KeyT &Key) {
|
||||||
@ -261,7 +276,7 @@ public:
|
|||||||
if (LookupBucketFor(Key, TheBucket))
|
if (LookupBucketFor(Key, TheBucket))
|
||||||
return *TheBucket;
|
return *TheBucket;
|
||||||
|
|
||||||
return *InsertIntoBucket(std::move(Key), ValueT(), TheBucket);
|
return *InsertIntoBucket(TheBucket, std::move(Key));
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueT &operator[](KeyT &&Key) {
|
ValueT &operator[](KeyT &&Key) {
|
||||||
@ -429,36 +444,19 @@ private:
|
|||||||
static_cast<DerivedT *>(this)->shrink_and_clear();
|
static_cast<DerivedT *>(this)->shrink_and_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename KeyArg, typename... ValueArgs>
|
||||||
BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
|
BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
|
||||||
BucketT *TheBucket) {
|
ValueArgs &&... Values) {
|
||||||
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
|
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
|
||||||
|
|
||||||
TheBucket->getFirst() = Key;
|
TheBucket->getFirst() = std::forward<KeyArg>(Key);
|
||||||
::new (&TheBucket->getSecond()) ValueT(Value);
|
::new (&TheBucket->getSecond()) ValueT(std::forward<ValueArgs>(Values)...);
|
||||||
return TheBucket;
|
|
||||||
}
|
|
||||||
|
|
||||||
BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
|
|
||||||
BucketT *TheBucket) {
|
|
||||||
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
|
|
||||||
|
|
||||||
TheBucket->getFirst() = Key;
|
|
||||||
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
|
|
||||||
return TheBucket;
|
|
||||||
}
|
|
||||||
|
|
||||||
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) {
|
|
||||||
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
|
|
||||||
|
|
||||||
TheBucket->getFirst() = std::move(Key);
|
|
||||||
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
|
|
||||||
return TheBucket;
|
return TheBucket;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename LookupKeyT>
|
template <typename LookupKeyT>
|
||||||
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, LookupKeyT &Lookup,
|
BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
|
||||||
BucketT *TheBucket) {
|
ValueT &&Value, LookupKeyT &Lookup) {
|
||||||
TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
|
TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
|
||||||
|
|
||||||
TheBucket->getFirst() = std::move(Key);
|
TheBucket->getFirst() = std::move(Key);
|
||||||
|
@ -619,4 +619,14 @@ TEST(DenseMapCustomTest, SmallDenseMapGrowTest) {
|
|||||||
EXPECT_TRUE(map.find(32) == map.end());
|
EXPECT_TRUE(map.find(32) == map.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DenseMapCustomTest, TryEmplaceTest) {
|
||||||
|
DenseMap<int, std::unique_ptr<int>> Map;
|
||||||
|
std::unique_ptr<int> P(new int(2));
|
||||||
|
auto Try1 = Map.try_emplace(0, new int(1));
|
||||||
|
EXPECT_TRUE(Try1.second);
|
||||||
|
auto Try2 = Map.try_emplace(0, std::move(P));
|
||||||
|
EXPECT_FALSE(Try2.second);
|
||||||
|
EXPECT_EQ(Try1.first, Try2.first);
|
||||||
|
EXPECT_NE(nullptr, P);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user