llvm.org GIT mirror llvm / 1a324fd
[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 Benjamin Kramer 3 years ago
2 changed file(s) with 50 addition(s) and 42 deletion(s). Raw diff Collapse all Expand all
168168 // If the key is already in the map, it returns false and doesn't update the
169169 // value.
170170 std::pair insert(const std::pair &KV) {
171 BucketT *TheBucket;
172 if (LookupBucketFor(KV.first, TheBucket))
173 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
174 false); // Already in map.
175
176 // Otherwise, insert the new element.
177 TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);
178 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
179 true);
171 return try_emplace(KV.first, KV.second);
180172 }
181173
182174 // Inserts key,value pair into the map if the key isn't already in the map.
183175 // If the key is already in the map, it returns false and doesn't update the
184176 // value.
185177 std::pair insert(std::pair &&KV) {
178 return try_emplace(std::move(KV.first), std::move(KV.second));
179 }
180
181 // Inserts key,value pair into the map if the key isn't already in the map.
182 // The value is constructed in-place if the key is not in the map, otherwise
183 // it is not moved.
184 template
185 std::pair try_emplace(KeyT &&Key, Ts &&... Args) {
186186 BucketT *TheBucket;
187 if (LookupBucketFor(KV.first, TheBucket))
187 if (LookupBucketFor(Key, TheBucket))
188188 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
189189 false); // Already in map.
190190
191191 // Otherwise, insert the new element.
192 TheBucket = InsertIntoBucket(std::move(KV.first),
193 std::move(KV.second),
194 TheBucket);
192 TheBucket =
193 InsertIntoBucket(TheBucket, std::move(Key), std::forward(Args)...);
194 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
195 true);
196 }
197
198 // Inserts key,value pair into the map if the key isn't already in the map.
199 // The value is constructed in-place if the key is not in the map, otherwise
200 // it is not moved.
201 template
202 std::pair try_emplace(const KeyT &Key, Ts &&... Args) {
203 BucketT *TheBucket;
204 if (LookupBucketFor(Key, TheBucket))
205 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
206 false); // Already in map.
207
208 // Otherwise, insert the new element.
209 TheBucket = InsertIntoBucket(TheBucket, Key, std::forward(Args)...);
195210 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
196211 true);
197212 }
210225 false); // Already in map.
211226
212227 // Otherwise, insert the new element.
213 TheBucket = InsertIntoBucket(std::move(KV.first), std::move(KV.second), Val,
214 TheBucket);
228 TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
229 std::move(KV.second), Val);
215230 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
216231 true);
217232 }
248263 if (LookupBucketFor(Key, TheBucket))
249264 return *TheBucket;
250265
251 return *InsertIntoBucket(Key, ValueT(), TheBucket);
266 return *InsertIntoBucket(TheBucket, Key);
252267 }
253268
254269 ValueT &operator[](const KeyT &Key) {
260275 if (LookupBucketFor(Key, TheBucket))
261276 return *TheBucket;
262277
263 return *InsertIntoBucket(std::move(Key), ValueT(), TheBucket);
278 return *InsertIntoBucket(TheBucket, std::move(Key));
264279 }
265280
266281 ValueT &operator[](KeyT &&Key) {
428443 static_cast(this)->shrink_and_clear();
429444 }
430445
431
432 BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
433 BucketT *TheBucket) {
446 template
447 BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
448 ValueArgs &&... Values) {
434449 TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
435450
436 TheBucket->getFirst() = Key;
437 ::new (&TheBucket->getSecond()) ValueT(Value);
451 TheBucket->getFirst() = std::forward(Key);
452 ::new (&TheBucket->getSecond()) ValueT(std::forward(Values)...);
438453 return TheBucket;
439454 }
440455
441 BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
442 BucketT *TheBucket) {
443 TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
444
445 TheBucket->getFirst() = Key;
446 ::new (&TheBucket->getSecond()) ValueT(std::move(Value));
447 return TheBucket;
448 }
449
450 BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) {
451 TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
452
453 TheBucket->getFirst() = std::move(Key);
454 ::new (&TheBucket->getSecond()) ValueT(std::move(Value));
455 return TheBucket;
456 }
457
458456 template
459 BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, LookupKeyT &Lookup,
460 BucketT *TheBucket) {
457 BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
458 ValueT &&Value, LookupKeyT &Lookup) {
461459 TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
462460
463461 TheBucket->getFirst() = std::move(Key);
618618 EXPECT_TRUE(map.find(32) == map.end());
619619 }
620620
621 }
621 TEST(DenseMapCustomTest, TryEmplaceTest) {
622 DenseMap> Map;
623 std::unique_ptr P(new int(2));
624 auto Try1 = Map.try_emplace(0, new int(1));
625 EXPECT_TRUE(Try1.second);
626 auto Try2 = Map.try_emplace(0, std::move(P));
627 EXPECT_FALSE(Try2.second);
628 EXPECT_EQ(Try1.first, Try2.first);
629 EXPECT_NE(nullptr, P);
630 }
631 }