1// Inserts key,value pair into the map if the key isn't already in the map. 2// The value is constructed in-place if the key is not in the map, otherwise 3// it is not moved. 4 template <typename... Ts> 5 std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) { 6 BucketT *TheBucket; 7if (LookupBucketFor(Key, TheBucket))// 关联的 key 在不在 bucket 中 8return std::make_pair( 9 makeIterator(TheBucket, getBucketsEnd(), true), 10false); // Already in map.已经在了 12// Otherwise, insert the new element. 13// key 是新的,把 key 插入 bucket 中 14 TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...); 15return std::make_pair( 16 makeIterator(TheBucket, getBucketsEnd(), true), 17true); 18 }
1 template<typename LookupKeyT> 2bool LookupBucketFor(const LookupKeyT &Val, 3const BucketT *&FoundBucket) const { 4const BucketT *BucketsPtr = getBuckets(); 5constunsigned NumBuckets = getNumBuckets(); 7if (NumBuckets == 0) { 8 FoundBucket = nullptr; 9returnfalse; 10 } 12// FoundTombstone - Keep track of whether we find a tombstone while probing. 13const BucketT *FoundTombstone = nullptr; 14const KeyT EmptyKey = getEmptyKey(); 15const KeyT TombstoneKey = getTombstoneKey(); 16 assert(!KeyInfoT::isEqual(Val, EmptyKey) && 17 !KeyInfoT::isEqual(Val, TombstoneKey) && 18"Empty/Tombstone value shouldn't be inserted into map!"); 20unsigned BucketNo = getHashValue(Val) & (NumBuckets-1);// 哈希函数 算下标 21unsigned ProbeAmt = 1; 22// 开始 while 23while (true) { 24const BucketT *ThisBucket = BucketsPtr + BucketNo;// 指针位置移动 25// Found Val's bucket? If so, return it. 26// 找到了 value 的 bucket 则返回 bucket 赋给外部的值->FoundBucket,然后return寻找的结果为true 27if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) { 28 FoundBucket = ThisBucket; 29returntrue; 30 } 32// If we found an empty bucket, the key doesn't exist in the set. 33// Insert it and return the default value. 34// 找到了一个空的 bucket --> 插入一个空的 bucket 并赋给 FoundBucket,然后return查找结果为false 35if (LLVM_LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) { 36// If we've already seen a tombstone while probing, fill it in instead 37// of the empty bucket we eventually probed to. 38 FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket; 39returnfalse; 40 } 42// 处理 然后进行继续 while 循环操作 43// If this is a tombstone, remember it. If Val ends up not in the map, we 44// prefer to return it than something that would require more probing. 45// Ditto for zero values. 46if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) && 47 !FoundTombstone) 48 FoundTombstone = ThisBucket; // Remember the first tombstone found. 49if (ValueInfoT::isPurgeable(ThisBucket->getSecond()) && !FoundTombstone) 50 FoundTombstone = ThisBucket; 52// Otherwise, it's a hash collision or a tombstone, continue quadratic 53// probing. 54if (ProbeAmt > NumBuckets) { 55 FatalCorruptHashTables(BucketsPtr, NumBuckets); 56 } 57 BucketNo += ProbeAmt++; 58 BucketNo &= (NumBuckets-1); 59 } 60 }
1 template <typename LookupKeyT> 2 BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup, 3 BucketT *TheBucket) { 4// If the load of the hash table is more than 3/4, or if fewer than 1/8 of 5// the buckets are empty (meaning that many are filled with tombstones), 6// grow the table. 7// 8// The later case is tricky. For example, if we had one empty bucket with 9// tons of tombstones, failing lookups (e.g. for insertion) would have to 10// probe almost the entire table until it found the empty bucket. If the 11// table completely filled with tombstones, no lookup would ever succeed, 12// causing infinite loops in lookup. 13unsigned NewNumEntries = getNumEntries() + 1; 14unsigned NumBuckets = getNumBuckets(); 15if (LLVM_UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) { 16 this->grow(NumBuckets * 2); 17 LookupBucketFor(Lookup, TheBucket); 18 NumBuckets = getNumBuckets(); 19 } elseif (LLVM_UNLIKELY(NumBuckets-(NewNumEntries+getNumTombstones()) <= 20 NumBuckets/8)) { 21 this->grow(NumBuckets); 22 LookupBucketFor(Lookup, TheBucket); 23 } 24 ASSERT(TheBucket); 26// Only update the state after we've grown our bucket space appropriately 27// so that when growing buckets we have self-consistent entry count. 28// If we are writing over a tombstone or zero value, remember this. 29if (KeyInfoT::isEqual(TheBucket->getFirst(), getEmptyKey())) { 30// Replacing an empty bucket. 31 incrementNumEntries(); 32 } elseif (KeyInfoT::isEqual(TheBucket->getFirst(), getTombstoneKey())) { 33// Replacing a tombstone. 34 incrementNumEntries(); 35 decrementNumTombstones(); 36 } else { 37// we should be purging a zero. No accounting changes. 38 ASSERT(ValueInfoT::isPurgeable(TheBucket->getSecond())); 39 TheBucket->getSecond().~ValueT(); 40 } 42return TheBucket; 43 }