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