1 //===- StringMap.h - String Hash table map interface ------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file defines the StringMap class. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_ADT_STRINGMAP_H 15 #define LLVM_ADT_STRINGMAP_H 16 17 #include "llvm/ADT/StringMapEntry.h" 18 #include "llvm/ADT/iterator.h" 19 #include "llvm/Support/AllocatorBase.h" 20 #include "llvm/Support/Compiler.h" 21 #include "llvm/Support/PointerLikeTypeTraits.h" 22 #include <initializer_list> 23 #include <iterator> 24 25 namespace llvm { 26 27 template <typename ValueTy> class StringMapConstIterator; 28 template <typename ValueTy> class StringMapIterator; 29 template <typename ValueTy> class StringMapKeyIterator; 30 31 /// StringMapImpl - This is the base class of StringMap that is shared among 32 /// all of its instantiations. 33 class StringMapImpl { 34 protected: 35 // Array of NumBuckets pointers to entries, null pointers are holes. 36 // TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed 37 // by an array of the actual hash values as unsigned integers. 38 StringMapEntryBase **TheTable = nullptr; 39 unsigned NumBuckets = 0; 40 unsigned NumItems = 0; 41 unsigned NumTombstones = 0; 42 unsigned ItemSize; 43 44 protected: StringMapImpl(unsigned itemSize)45 explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {} StringMapImpl(StringMapImpl && RHS)46 StringMapImpl(StringMapImpl &&RHS) 47 : TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets), 48 NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones), 49 ItemSize(RHS.ItemSize) { 50 RHS.TheTable = nullptr; 51 RHS.NumBuckets = 0; 52 RHS.NumItems = 0; 53 RHS.NumTombstones = 0; 54 } 55 56 LLVM_ABI StringMapImpl(unsigned InitSize, unsigned ItemSize); ~StringMapImpl()57 ~StringMapImpl() { free(TheTable); } 58 LLVM_ABI unsigned RehashTable(unsigned BucketNo = 0); 59 60 /// LookupBucketFor - Look up the bucket that the specified string should end 61 /// up in. If it already exists as a key in the map, the Item pointer for the 62 /// specified bucket will be non-null. Otherwise, it will be null. In either 63 /// case, the FullHashValue field of the bucket will be set to the hash value 64 /// of the string. LookupBucketFor(StringRef Key)65 unsigned LookupBucketFor(StringRef Key) { 66 return LookupBucketFor(Key, hash(Key)); 67 } 68 69 /// Overload that explicitly takes precomputed hash(Key). 70 LLVM_ABI unsigned LookupBucketFor(StringRef Key, uint32_t FullHashValue); 71 72 /// FindKey - Look up the bucket that contains the specified key. If it exists 73 /// in the map, return the bucket number of the key. Otherwise return -1. 74 /// This does not modify the map. FindKey(StringRef Key)75 int FindKey(StringRef Key) const { return FindKey(Key, hash(Key)); } 76 77 /// Overload that explicitly takes precomputed hash(Key). 78 LLVM_ABI int FindKey(StringRef Key, uint32_t FullHashValue) const; 79 80 /// RemoveKey - Remove the specified StringMapEntry from the table, but do not 81 /// delete it. This aborts if the value isn't in the table. 82 LLVM_ABI void RemoveKey(StringMapEntryBase *V); 83 84 /// RemoveKey - Remove the StringMapEntry for the specified key from the 85 /// table, returning it. If the key is not in the table, this returns null. 86 LLVM_ABI StringMapEntryBase *RemoveKey(StringRef Key); 87 88 /// Allocate the table with the specified number of buckets and otherwise 89 /// setup the map as empty. 90 LLVM_ABI void init(unsigned Size); 91 92 public: 93 static constexpr uintptr_t TombstoneIntVal = 94 static_cast<uintptr_t>(-1) 95 << PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable; 96 getTombstoneVal()97 static StringMapEntryBase *getTombstoneVal() { 98 return reinterpret_cast<StringMapEntryBase *>(TombstoneIntVal); 99 } 100 getNumBuckets()101 unsigned getNumBuckets() const { return NumBuckets; } getNumItems()102 unsigned getNumItems() const { return NumItems; } 103 empty()104 bool empty() const { return NumItems == 0; } size()105 unsigned size() const { return NumItems; } 106 107 /// Returns the hash value that will be used for the given string. 108 /// This allows precomputing the value and passing it explicitly 109 /// to some of the functions. 110 /// The implementation of this function is not guaranteed to be stable 111 /// and may change. 112 LLVM_ABI static uint32_t hash(StringRef Key); 113 swap(StringMapImpl & Other)114 void swap(StringMapImpl &Other) { 115 std::swap(TheTable, Other.TheTable); 116 std::swap(NumBuckets, Other.NumBuckets); 117 std::swap(NumItems, Other.NumItems); 118 std::swap(NumTombstones, Other.NumTombstones); 119 } 120 }; 121 122 /// StringMap - This is an unconventional map that is specialized for handling 123 /// keys that are "strings", which are basically ranges of bytes. This does some 124 /// funky memory allocation and hashing things to make it extremely efficient, 125 /// storing the string data *after* the value in the map. 126 template <typename ValueTy, typename AllocatorTy = MallocAllocator> 127 class LLVM_ALLOCATORHOLDER_EMPTYBASE StringMap 128 : public StringMapImpl, 129 private detail::AllocatorHolder<AllocatorTy> { 130 using AllocTy = detail::AllocatorHolder<AllocatorTy>; 131 132 public: 133 using MapEntryTy = StringMapEntry<ValueTy>; 134 StringMap()135 StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {} 136 StringMap(unsigned InitialSize)137 explicit StringMap(unsigned InitialSize) 138 : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {} 139 StringMap(AllocatorTy A)140 explicit StringMap(AllocatorTy A) 141 : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), AllocTy(A) {} 142 StringMap(unsigned InitialSize,AllocatorTy A)143 StringMap(unsigned InitialSize, AllocatorTy A) 144 : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))), 145 AllocTy(A) {} 146 StringMap(std::initializer_list<std::pair<StringRef,ValueTy>> List)147 StringMap(std::initializer_list<std::pair<StringRef, ValueTy>> List) 148 : StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) { 149 insert(List); 150 } 151 StringMap(StringMap && RHS)152 StringMap(StringMap &&RHS) 153 : StringMapImpl(std::move(RHS)), AllocTy(std::move(RHS.getAllocator())) {} 154 StringMap(const StringMap & RHS)155 StringMap(const StringMap &RHS) 156 : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), 157 AllocTy(RHS.getAllocator()) { 158 if (RHS.empty()) 159 return; 160 161 // Allocate TheTable of the same size as RHS's TheTable, and set the 162 // sentinel appropriately (and NumBuckets). 163 init(RHS.NumBuckets); 164 unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1), 165 *RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1); 166 167 NumItems = RHS.NumItems; 168 NumTombstones = RHS.NumTombstones; 169 for (unsigned I = 0, E = NumBuckets; I != E; ++I) { 170 StringMapEntryBase *Bucket = RHS.TheTable[I]; 171 if (!Bucket || Bucket == getTombstoneVal()) { 172 TheTable[I] = Bucket; 173 continue; 174 } 175 176 TheTable[I] = MapEntryTy::create( 177 static_cast<MapEntryTy *>(Bucket)->getKey(), getAllocator(), 178 static_cast<MapEntryTy *>(Bucket)->getValue()); 179 HashTable[I] = RHSHashTable[I]; 180 } 181 182 // Note that here we've copied everything from the RHS into this object, 183 // tombstones included. We could, instead, have re-probed for each key to 184 // instantiate this new object without any tombstone buckets. The 185 // assumption here is that items are rarely deleted from most StringMaps, 186 // and so tombstones are rare, so the cost of re-probing for all inputs is 187 // not worthwhile. 188 } 189 190 StringMap &operator=(StringMap RHS) { 191 StringMapImpl::swap(RHS); 192 std::swap(getAllocator(), RHS.getAllocator()); 193 return *this; 194 } 195 ~StringMap()196 ~StringMap() { 197 // Delete all the elements in the map, but don't reset the elements 198 // to default values. This is a copy of clear(), but avoids unnecessary 199 // work not required in the destructor. 200 if (!empty()) { 201 for (unsigned I = 0, E = NumBuckets; I != E; ++I) { 202 StringMapEntryBase *Bucket = TheTable[I]; 203 if (Bucket && Bucket != getTombstoneVal()) { 204 static_cast<MapEntryTy *>(Bucket)->Destroy(getAllocator()); 205 } 206 } 207 } 208 } 209 210 using AllocTy::getAllocator; 211 212 using key_type = const char *; 213 using mapped_type = ValueTy; 214 using value_type = StringMapEntry<ValueTy>; 215 using size_type = size_t; 216 217 using const_iterator = StringMapConstIterator<ValueTy>; 218 using iterator = StringMapIterator<ValueTy>; 219 begin()220 iterator begin() { return iterator(TheTable, NumBuckets == 0); } end()221 iterator end() { return iterator(TheTable + NumBuckets, true); } begin()222 const_iterator begin() const { 223 return const_iterator(TheTable, NumBuckets == 0); 224 } end()225 const_iterator end() const { 226 return const_iterator(TheTable + NumBuckets, true); 227 } 228 keys()229 iterator_range<StringMapKeyIterator<ValueTy>> keys() const { 230 return make_range(StringMapKeyIterator<ValueTy>(begin()), 231 StringMapKeyIterator<ValueTy>(end())); 232 } 233 find(StringRef Key)234 iterator find(StringRef Key) { return find(Key, hash(Key)); } 235 find(StringRef Key,uint32_t FullHashValue)236 iterator find(StringRef Key, uint32_t FullHashValue) { 237 int Bucket = FindKey(Key, FullHashValue); 238 if (Bucket == -1) 239 return end(); 240 return iterator(TheTable + Bucket, true); 241 } 242 find(StringRef Key)243 const_iterator find(StringRef Key) const { return find(Key, hash(Key)); } 244 find(StringRef Key,uint32_t FullHashValue)245 const_iterator find(StringRef Key, uint32_t FullHashValue) const { 246 int Bucket = FindKey(Key, FullHashValue); 247 if (Bucket == -1) 248 return end(); 249 return const_iterator(TheTable + Bucket, true); 250 } 251 252 /// lookup - Return the entry for the specified key, or a default 253 /// constructed value if no such entry exists. lookup(StringRef Key)254 ValueTy lookup(StringRef Key) const { 255 const_iterator Iter = find(Key); 256 if (Iter != end()) 257 return Iter->second; 258 return ValueTy(); 259 } 260 261 /// at - Return the entry for the specified key, or abort if no such 262 /// entry exists. at(StringRef Val)263 const ValueTy &at(StringRef Val) const { 264 auto Iter = this->find(std::move(Val)); 265 assert(Iter != this->end() && "StringMap::at failed due to a missing key"); 266 return Iter->second; 267 } 268 269 /// Lookup the ValueTy for the \p Key, or create a default constructed value 270 /// if the key is not in the map. 271 ValueTy &operator[](StringRef Key) { return try_emplace(Key).first->second; } 272 273 /// contains - Return true if the element is in the map, false otherwise. contains(StringRef Key)274 bool contains(StringRef Key) const { return find(Key) != end(); } 275 276 /// count - Return 1 if the element is in the map, 0 otherwise. count(StringRef Key)277 size_type count(StringRef Key) const { return contains(Key) ? 1 : 0; } 278 279 template <typename InputTy> count(const StringMapEntry<InputTy> & MapEntry)280 size_type count(const StringMapEntry<InputTy> &MapEntry) const { 281 return count(MapEntry.getKey()); 282 } 283 284 /// equal - check whether both of the containers are equal. 285 bool operator==(const StringMap &RHS) const { 286 if (size() != RHS.size()) 287 return false; 288 289 for (const auto &KeyValue : *this) { 290 auto FindInRHS = RHS.find(KeyValue.getKey()); 291 292 if (FindInRHS == RHS.end()) 293 return false; 294 295 if constexpr (!std::is_same_v<ValueTy, std::nullopt_t>) { 296 if (!(KeyValue.getValue() == FindInRHS->getValue())) 297 return false; 298 } 299 } 300 301 return true; 302 } 303 304 bool operator!=(const StringMap &RHS) const { return !(*this == RHS); } 305 306 /// insert - Insert the specified key/value pair into the map. If the key 307 /// already exists in the map, return false and ignore the request, otherwise 308 /// insert it and return true. insert(MapEntryTy * KeyValue)309 bool insert(MapEntryTy *KeyValue) { 310 unsigned BucketNo = LookupBucketFor(KeyValue->getKey()); 311 StringMapEntryBase *&Bucket = TheTable[BucketNo]; 312 if (Bucket && Bucket != getTombstoneVal()) 313 return false; // Already exists in map. 314 315 if (Bucket == getTombstoneVal()) 316 --NumTombstones; 317 Bucket = KeyValue; 318 ++NumItems; 319 assert(NumItems + NumTombstones <= NumBuckets); 320 321 RehashTable(); 322 return true; 323 } 324 325 /// insert - Inserts the specified key/value pair into the map if the key 326 /// isn't already in the map. The bool component of the returned pair is true 327 /// if and only if the insertion takes place, and the iterator component of 328 /// the pair points to the element with key equivalent to the key of the pair. insert(std::pair<StringRef,ValueTy> KV)329 std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) { 330 return try_emplace_with_hash(KV.first, hash(KV.first), 331 std::move(KV.second)); 332 } 333 insert(std::pair<StringRef,ValueTy> KV,uint32_t FullHashValue)334 std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV, 335 uint32_t FullHashValue) { 336 return try_emplace_with_hash(KV.first, FullHashValue, std::move(KV.second)); 337 } 338 339 /// Inserts elements from range [first, last). If multiple elements in the 340 /// range have keys that compare equivalent, it is unspecified which element 341 /// is inserted . insert(InputIt First,InputIt Last)342 template <typename InputIt> void insert(InputIt First, InputIt Last) { 343 for (InputIt It = First; It != Last; ++It) 344 insert(*It); 345 } 346 347 /// Inserts elements from initializer list ilist. If multiple elements in 348 /// the range have keys that compare equivalent, it is unspecified which 349 /// element is inserted insert(std::initializer_list<std::pair<StringRef,ValueTy>> List)350 void insert(std::initializer_list<std::pair<StringRef, ValueTy>> List) { 351 insert(List.begin(), List.end()); 352 } 353 354 /// Inserts an element or assigns to the current element if the key already 355 /// exists. The return type is the same as try_emplace. 356 template <typename V> insert_or_assign(StringRef Key,V && Val)357 std::pair<iterator, bool> insert_or_assign(StringRef Key, V &&Val) { 358 auto Ret = try_emplace(Key, std::forward<V>(Val)); 359 if (!Ret.second) 360 Ret.first->second = std::forward<V>(Val); 361 return Ret; 362 } 363 364 /// Emplace a new element for the specified key into the map if the key isn't 365 /// already in the map. The bool component of the returned pair is true 366 /// if and only if the insertion takes place, and the iterator component of 367 /// the pair points to the element with key equivalent to the key of the pair. 368 template <typename... ArgsTy> try_emplace(StringRef Key,ArgsTy &&...Args)369 std::pair<iterator, bool> try_emplace(StringRef Key, ArgsTy &&...Args) { 370 return try_emplace_with_hash(Key, hash(Key), std::forward<ArgsTy>(Args)...); 371 } 372 373 template <typename... ArgsTy> try_emplace_with_hash(StringRef Key,uint32_t FullHashValue,ArgsTy &&...Args)374 std::pair<iterator, bool> try_emplace_with_hash(StringRef Key, 375 uint32_t FullHashValue, 376 ArgsTy &&...Args) { 377 unsigned BucketNo = LookupBucketFor(Key, FullHashValue); 378 StringMapEntryBase *&Bucket = TheTable[BucketNo]; 379 if (Bucket && Bucket != getTombstoneVal()) 380 return std::make_pair(iterator(TheTable + BucketNo, false), 381 false); // Already exists in map. 382 383 if (Bucket == getTombstoneVal()) 384 --NumTombstones; 385 Bucket = 386 MapEntryTy::create(Key, getAllocator(), std::forward<ArgsTy>(Args)...); 387 ++NumItems; 388 assert(NumItems + NumTombstones <= NumBuckets); 389 390 BucketNo = RehashTable(BucketNo); 391 return std::make_pair(iterator(TheTable + BucketNo, false), true); 392 } 393 394 // clear - Empties out the StringMap clear()395 void clear() { 396 if (empty()) 397 return; 398 399 // Zap all values, resetting the keys back to non-present (not tombstone), 400 // which is safe because we're removing all elements. 401 for (unsigned I = 0, E = NumBuckets; I != E; ++I) { 402 StringMapEntryBase *&Bucket = TheTable[I]; 403 if (Bucket && Bucket != getTombstoneVal()) { 404 static_cast<MapEntryTy *>(Bucket)->Destroy(getAllocator()); 405 } 406 Bucket = nullptr; 407 } 408 409 NumItems = 0; 410 NumTombstones = 0; 411 } 412 413 /// remove - Remove the specified key/value pair from the map, but do not 414 /// erase it. This aborts if the key is not in the map. remove(MapEntryTy * KeyValue)415 void remove(MapEntryTy *KeyValue) { RemoveKey(KeyValue); } 416 erase(iterator I)417 void erase(iterator I) { 418 MapEntryTy &V = *I; 419 remove(&V); 420 V.Destroy(getAllocator()); 421 } 422 erase(StringRef Key)423 bool erase(StringRef Key) { 424 iterator I = find(Key); 425 if (I == end()) 426 return false; 427 erase(I); 428 return true; 429 } 430 }; 431 432 template <typename DerivedTy, typename ValueTy> 433 class StringMapIterBase 434 : public iterator_facade_base<DerivedTy, std::forward_iterator_tag, 435 ValueTy> { 436 protected: 437 StringMapEntryBase **Ptr = nullptr; 438 439 public: 440 StringMapIterBase() = default; 441 442 explicit StringMapIterBase(StringMapEntryBase **Bucket, 443 bool NoAdvance = false) Ptr(Bucket)444 : Ptr(Bucket) { 445 if (!NoAdvance) 446 AdvancePastEmptyBuckets(); 447 } 448 449 DerivedTy &operator=(const DerivedTy &Other) { 450 Ptr = Other.Ptr; 451 return static_cast<DerivedTy &>(*this); 452 } 453 454 friend bool operator==(const DerivedTy &LHS, const DerivedTy &RHS) { 455 return LHS.Ptr == RHS.Ptr; 456 } 457 458 DerivedTy &operator++() { // Preincrement 459 ++Ptr; 460 AdvancePastEmptyBuckets(); 461 return static_cast<DerivedTy &>(*this); 462 } 463 464 DerivedTy operator++(int) { // Post-increment 465 DerivedTy Tmp(Ptr); 466 ++*this; 467 return Tmp; 468 } 469 470 private: AdvancePastEmptyBuckets()471 void AdvancePastEmptyBuckets() { 472 while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal()) 473 ++Ptr; 474 } 475 }; 476 477 template <typename ValueTy> 478 class StringMapConstIterator 479 : public StringMapIterBase<StringMapConstIterator<ValueTy>, 480 const StringMapEntry<ValueTy>> { 481 using base = StringMapIterBase<StringMapConstIterator<ValueTy>, 482 const StringMapEntry<ValueTy>>; 483 484 public: 485 StringMapConstIterator() = default; 486 explicit StringMapConstIterator(StringMapEntryBase **Bucket, 487 bool NoAdvance = false) base(Bucket,NoAdvance)488 : base(Bucket, NoAdvance) {} 489 490 const StringMapEntry<ValueTy> &operator*() const { 491 return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr); 492 } 493 }; 494 495 template <typename ValueTy> 496 class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>, 497 StringMapEntry<ValueTy>> { 498 using base = 499 StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>; 500 501 public: 502 StringMapIterator() = default; 503 explicit StringMapIterator(StringMapEntryBase **Bucket, 504 bool NoAdvance = false) base(Bucket,NoAdvance)505 : base(Bucket, NoAdvance) {} 506 507 StringMapEntry<ValueTy> &operator*() const { 508 return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr); 509 } 510 511 operator StringMapConstIterator<ValueTy>() const { 512 return StringMapConstIterator<ValueTy>(this->Ptr, true); 513 } 514 }; 515 516 template <typename ValueTy> 517 class StringMapKeyIterator 518 : public iterator_adaptor_base<StringMapKeyIterator<ValueTy>, 519 StringMapConstIterator<ValueTy>, 520 std::forward_iterator_tag, StringRef> { 521 using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>, 522 StringMapConstIterator<ValueTy>, 523 std::forward_iterator_tag, StringRef>; 524 525 public: 526 StringMapKeyIterator() = default; StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)527 explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter) 528 : base(std::move(Iter)) {} 529 530 StringRef operator*() const { return this->wrapped()->getKey(); } 531 }; 532 533 } // end namespace llvm 534 535 #endif // LLVM_ADT_STRINGMAP_H 536