1 //===- StringMapEntry.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 StringMapEntry class - it is intended to be a low 11 /// dependency implementation detail of StringMap that is more suitable for 12 /// inclusion in public headers than StringMap.h itself is. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_ADT_STRINGMAPENTRY_H 17 #define LLVM_ADT_STRINGMAPENTRY_H 18 19 #include "llvm/ADT/None.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/ADT/STLFunctionalExtras.h" 22 23 namespace llvm { 24 25 /// StringMapEntryBase - Shared base class of StringMapEntry instances. 26 class StringMapEntryBase { 27 size_t keyLength; 28 29 public: 30 explicit StringMapEntryBase(size_t keyLength) : keyLength(keyLength) {} 31 32 size_t getKeyLength() const { return keyLength; } 33 34 protected: 35 /// Helper to tail-allocate \p Key. It'd be nice to generalize this so it 36 /// could be reused elsewhere, maybe even taking an llvm::function_ref to 37 /// type-erase the allocator and put it in a source file. 38 template <typename AllocatorTy> 39 static void *allocateWithKey(size_t EntrySize, size_t EntryAlign, 40 StringRef Key, AllocatorTy &Allocator); 41 }; 42 43 // Define out-of-line to dissuade inlining. 44 template <typename AllocatorTy> 45 void *StringMapEntryBase::allocateWithKey(size_t EntrySize, size_t EntryAlign, 46 StringRef Key, 47 AllocatorTy &Allocator) { 48 size_t KeyLength = Key.size(); 49 50 // Allocate a new item with space for the string at the end and a null 51 // terminator. 52 size_t AllocSize = EntrySize + KeyLength + 1; 53 void *Allocation = Allocator.Allocate(AllocSize, EntryAlign); 54 assert(Allocation && "Unhandled out-of-memory"); 55 56 // Copy the string information. 57 char *Buffer = reinterpret_cast<char *>(Allocation) + EntrySize; 58 if (KeyLength > 0) 59 ::memcpy(Buffer, Key.data(), KeyLength); 60 Buffer[KeyLength] = 0; // Null terminate for convenience of clients. 61 return Allocation; 62 } 63 64 /// StringMapEntryStorage - Holds the value in a StringMapEntry. 65 /// 66 /// Factored out into a separate base class to make it easier to specialize. 67 /// This is primarily intended to support StringSet, which doesn't need a value 68 /// stored at all. 69 template <typename ValueTy> 70 class StringMapEntryStorage : public StringMapEntryBase { 71 public: 72 ValueTy second; 73 74 explicit StringMapEntryStorage(size_t keyLength) 75 : StringMapEntryBase(keyLength), second() {} 76 template <typename... InitTy> 77 StringMapEntryStorage(size_t keyLength, InitTy &&... initVals) 78 : StringMapEntryBase(keyLength), 79 second(std::forward<InitTy>(initVals)...) {} 80 StringMapEntryStorage(StringMapEntryStorage &e) = delete; 81 82 const ValueTy &getValue() const { return second; } 83 ValueTy &getValue() { return second; } 84 85 void setValue(const ValueTy &V) { second = V; } 86 }; 87 88 template <> class StringMapEntryStorage<NoneType> : public StringMapEntryBase { 89 public: 90 explicit StringMapEntryStorage(size_t keyLength, NoneType = None) 91 : StringMapEntryBase(keyLength) {} 92 StringMapEntryStorage(StringMapEntryStorage &entry) = delete; 93 94 NoneType getValue() const { return None; } 95 }; 96 97 /// StringMapEntry - This is used to represent one value that is inserted into 98 /// a StringMap. It contains the Value itself and the key: the string length 99 /// and data. 100 template <typename ValueTy> 101 class StringMapEntry final : public StringMapEntryStorage<ValueTy> { 102 public: 103 using StringMapEntryStorage<ValueTy>::StringMapEntryStorage; 104 105 StringRef getKey() const { 106 return StringRef(getKeyData(), this->getKeyLength()); 107 } 108 109 /// getKeyData - Return the start of the string data that is the key for this 110 /// value. The string data is always stored immediately after the 111 /// StringMapEntry object. 112 const char *getKeyData() const { 113 return reinterpret_cast<const char *>(this + 1); 114 } 115 116 StringRef first() const { 117 return StringRef(getKeyData(), this->getKeyLength()); 118 } 119 120 /// Create a StringMapEntry for the specified key construct the value using 121 /// \p InitiVals. 122 template <typename AllocatorTy, typename... InitTy> 123 static StringMapEntry *Create(StringRef key, AllocatorTy &allocator, 124 InitTy &&... initVals) { 125 return new (StringMapEntryBase::allocateWithKey( 126 sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator)) 127 StringMapEntry(key.size(), std::forward<InitTy>(initVals)...); 128 } 129 130 /// GetStringMapEntryFromKeyData - Given key data that is known to be embedded 131 /// into a StringMapEntry, return the StringMapEntry itself. 132 static StringMapEntry &GetStringMapEntryFromKeyData(const char *keyData) { 133 char *ptr = const_cast<char *>(keyData) - sizeof(StringMapEntry<ValueTy>); 134 return *reinterpret_cast<StringMapEntry *>(ptr); 135 } 136 137 /// Destroy - Destroy this StringMapEntry, releasing memory back to the 138 /// specified allocator. 139 template <typename AllocatorTy> void Destroy(AllocatorTy &allocator) { 140 // Free memory referenced by the item. 141 size_t AllocSize = sizeof(StringMapEntry) + this->getKeyLength() + 1; 142 this->~StringMapEntry(); 143 allocator.Deallocate(static_cast<void *>(this), AllocSize, 144 alignof(StringMapEntry)); 145 } 146 }; 147 148 } // end namespace llvm 149 150 #endif // LLVM_ADT_STRINGMAPENTRY_H 151