LLVM 24.0.0git
MapVector.h
Go to the documentation of this file.
1//===- llvm/ADT/MapVector.h - Map w/ deterministic value order --*- 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 implements a map that provides insertion order iteration. The
11/// interface is purposefully minimal. The key is assumed to be cheap to copy
12/// and 2 copies are kept, one for indexing in a DenseMap, one for iteration in
13/// a SmallVector.
14///
15//===----------------------------------------------------------------------===//
16
17#ifndef LLVM_ADT_MAPVECTOR_H
18#define LLVM_ADT_MAPVECTOR_H
19
20#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/STLExtras.h"
24#include <cassert>
25#include <cstddef>
26#include <iterator>
27#include <type_traits>
28#include <utility>
29
30namespace llvm {
31
32/// This class implements a map that also provides access to all stored values
33/// in a deterministic order. The values are kept in a SmallVector<*, 0> and the
34/// mapping is done with DenseMap from Keys to indexes in that vector.
35template <typename KeyT, typename ValueT,
38 unsigned N = 0>
39class MapVector {
40public:
41 using key_type = KeyT;
42 using value_type = typename VectorType::value_type;
43 using size_type = typename VectorType::size_type;
44
45 using iterator = typename VectorType::iterator;
46 using const_iterator = typename VectorType::const_iterator;
47 using reverse_iterator = typename VectorType::reverse_iterator;
48 using const_reverse_iterator = typename VectorType::const_reverse_iterator;
49
50 /// Clear the MapVector and return the underlying vector.
51 [[nodiscard]] VectorType takeVector() {
52 Map.clear();
53 return std::move(Vector);
54 }
55
56 /// Returns an array reference of the underlying vector.
57 [[nodiscard]] ArrayRef<value_type> getArrayRef() const { return Vector; }
58
59 [[nodiscard]] size_type size() const { return Vector.size(); }
60
61 /// Grow the MapVector so that it can contain at least \p NumEntries items
62 /// before resizing again.
63 void reserve(size_type NumEntries) {
64 Map.reserve(NumEntries);
65 Vector.reserve(NumEntries);
66 }
67
68 [[nodiscard]] iterator begin() { return Vector.begin(); }
69 [[nodiscard]] const_iterator begin() const { return Vector.begin(); }
70 [[nodiscard]] iterator end() { return Vector.end(); }
71 [[nodiscard]] const_iterator end() const { return Vector.end(); }
72
73 [[nodiscard]] reverse_iterator rbegin() { return Vector.rbegin(); }
74 [[nodiscard]] const_reverse_iterator rbegin() const {
75 return Vector.rbegin();
76 }
77 [[nodiscard]] reverse_iterator rend() { return Vector.rend(); }
78 [[nodiscard]] const_reverse_iterator rend() const { return Vector.rend(); }
79
80 [[nodiscard]] bool empty() const { return Vector.empty(); }
81
82 [[nodiscard]] std::pair<KeyT, ValueT> &front() { return Vector.front(); }
83 [[nodiscard]] const std::pair<KeyT, ValueT> &front() const {
84 return Vector.front();
85 }
86 [[nodiscard]] std::pair<KeyT, ValueT> &back() { return Vector.back(); }
87 [[nodiscard]] const std::pair<KeyT, ValueT> &back() const {
88 return Vector.back();
89 }
90
91 void clear() {
92 Map.clear();
93 Vector.clear();
94 }
95
97 std::swap(Map, RHS.Map);
98 std::swap(Vector, RHS.Vector);
99 }
100
101 ValueT &operator[](const KeyT &Key) {
102 return try_emplace_impl(Key).first->second;
103 }
104
105 [[nodiscard]] auto keys() { return make_first_range(Vector); }
106 [[nodiscard]] auto keys() const { return make_first_range(Vector); }
107 [[nodiscard]] auto values() { return make_second_range(Vector); }
108 [[nodiscard]] auto values() const { return make_second_range(Vector); }
109
110 // Returns a copy of the value. Only allowed if ValueT is copyable.
111 [[nodiscard]] ValueT lookup(const KeyT &Key) const {
112 static_assert(std::is_copy_constructible_v<ValueT>,
113 "Cannot call lookup() if ValueT is not copyable.");
114 auto I = find(Key);
115 return I == end() ? ValueT() : I->second;
116 }
117
118 template <typename... Ts>
119 std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&...Args) {
120 return try_emplace_impl(Key, std::forward<Ts>(Args)...);
121 }
122 template <typename... Ts>
123 std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&...Args) {
124 return try_emplace_impl(std::move(Key), std::forward<Ts>(Args)...);
125 }
126
127 std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
128 return try_emplace_impl(KV.first, KV.second);
129 }
130 std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
131 return try_emplace_impl(std::move(KV.first), std::move(KV.second));
132 }
133
134 template <typename V>
135 std::pair<iterator, bool> insert_or_assign(const KeyT &Key, V &&Val) {
136 auto Ret = try_emplace(Key, std::forward<V>(Val));
137 if (!Ret.second)
138 Ret.first->second = std::forward<V>(Val);
139 return Ret;
140 }
141 template <typename V>
142 std::pair<iterator, bool> insert_or_assign(KeyT &&Key, V &&Val) {
143 auto Ret = try_emplace(std::move(Key), std::forward<V>(Val));
144 if (!Ret.second)
145 Ret.first->second = std::forward<V>(Val);
146 return Ret;
147 }
148
149 [[nodiscard]] bool contains(const KeyT &Key) const {
150 return find(Key) != end();
151 }
152
153 [[nodiscard]] size_type count(const KeyT &Key) const {
154 return contains(Key) ? 1 : 0;
155 }
156
157 [[nodiscard]] iterator find(const KeyT &Key) {
158 if constexpr (canBeSmall())
159 if (isSmall())
160 return findInVector(Vector, Key);
161
162 typename MapType::const_iterator Pos = Map.find(Key);
163 return Pos == Map.end() ? Vector.end() : (Vector.begin() + Pos->second);
164 }
165
166 [[nodiscard]] const_iterator find(const KeyT &Key) const {
167 if constexpr (canBeSmall())
168 if (isSmall())
169 return findInVector(Vector, Key);
170
171 typename MapType::const_iterator Pos = Map.find(Key);
172 return Pos == Map.end() ? Vector.end() : (Vector.begin() + Pos->second);
173 }
174
175 /// at - Return the entry for the specified key, or abort if no such
176 /// entry exists.
177 [[nodiscard]] ValueT &at(const KeyT &Key) {
178 auto I = find(Key);
179 assert(I != end() && "MapVector::at failed due to a missing key");
180 return I->second;
181 }
182
183 /// at - Return the entry for the specified key, or abort if no such
184 /// entry exists.
185 [[nodiscard]] const ValueT &at(const KeyT &Key) const {
186 auto I = find(Key);
187 assert(I != end() && "MapVector::at failed due to a missing key");
188 return I->second;
189 }
190
191 /// Remove the last element from the vector.
192 void pop_back() {
193 if constexpr (canBeSmall())
194 if (isSmall()) {
195 Vector.pop_back();
196 return;
197 }
198
199 typename MapType::iterator Pos = Map.find(Vector.back().first);
200 Map.erase(Pos);
201 Vector.pop_back();
202 }
203
204 /// Remove the element given by Iterator.
205 ///
206 /// Returns an iterator to the element following the one which was removed,
207 /// which may be end().
208 ///
209 /// \note This is a deceivingly expensive operation (linear time). It's
210 /// usually better to use \a remove_if() if possible.
211 typename VectorType::iterator erase(typename VectorType::iterator Iterator) {
212 if constexpr (canBeSmall())
213 if (isSmall())
214 return Vector.erase(Iterator);
215
216 Map.erase(Iterator->first);
217 auto Next = Vector.erase(Iterator);
218 if (Next == Vector.end())
219 return Next;
220
221 // Update indices in the map.
222 size_t Index = Next - Vector.begin();
223 for (auto &I : Map) {
224 assert(I.second != Index && "Index was already erased!");
225 if (I.second > Index)
226 --I.second;
227 }
228 return Next;
229 }
230
231 /// Remove all elements with the key value Key.
232 ///
233 /// Returns the number of elements removed.
235 auto Iterator = find(Key);
236 if (Iterator == end())
237 return 0;
238 erase(Iterator);
239 return 1;
240 }
241
242 /// Remove the elements that match the predicate.
243 ///
244 /// Erase all elements that match \c Pred in a single pass. Takes linear
245 /// time.
246 template <class Predicate> void remove_if(Predicate Pred);
247
248 /// Return the approximate size (in bytes) of the data structure.
249 /// This is just the raw memory used by MapVector.
250 /// If entries are pointers to objects, the size of the referenced objects
251 /// are not included.
252 [[nodiscard]] size_t getMemorySize() const {
253 return capacity_in_bytes(Map) + capacity_in_bytes(Vector);
254 }
255
256private:
257 template <typename VectorT, typename LookupKeyT>
258 [[nodiscard]] static auto findInVector(VectorT &Vec, const LookupKeyT &Key) {
259 return find_if(Vec, [&Key](const auto &P) { return P.first == Key; });
260 }
261
262 [[nodiscard]] static constexpr bool canBeSmall() { return N != 0; }
263
264 [[nodiscard]] bool isSmall() const { return Map.empty(); }
265
266 void makeBig() {
267 if constexpr (canBeSmall()) {
268 unsigned Index = 0;
269 for (const auto &entry : Vector)
270 Map[entry.first] = Index++;
271 }
272 }
273
274 MapType Map;
275 VectorType Vector;
276
277 static_assert(N <= 32, "Small size should be less than or equal to 32!");
278
279 static_assert(
280 std::is_integral_v<typename MapType::mapped_type>,
281 "The mapped_type of the specified Map must be an integral type");
282
283 template <typename KeyArgT, typename... Ts>
284 std::pair<iterator, bool> try_emplace_impl(KeyArgT &&Key, Ts &&...Args) {
285 if constexpr (canBeSmall())
286 if (isSmall()) {
287 auto I = findInVector(Vector, Key);
288 if (I != Vector.end())
289 return {I, false};
290 Vector.emplace_back(std::piecewise_construct,
291 std::forward_as_tuple(std::forward<KeyArgT>(Key)),
292 std::forward_as_tuple(std::forward<Ts>(Args)...));
293 if (Vector.size() > N)
294 makeBig();
295 return {std::prev(end()), true};
296 }
297
298 auto [It, Inserted] = Map.try_emplace(Key);
299 if (Inserted) {
300 It->second = Vector.size();
301 Vector.emplace_back(std::piecewise_construct,
302 std::forward_as_tuple(std::forward<KeyArgT>(Key)),
303 std::forward_as_tuple(std::forward<Ts>(Args)...));
304 return {std::prev(end()), true};
305 }
306 return {begin() + It->second, false};
307 }
308};
309
310template <typename KeyT, typename ValueT, typename MapType, typename VectorType,
311 unsigned N>
312template <class Function>
314 if constexpr (canBeSmall())
315 if (isSmall()) {
316 Vector.erase(llvm::remove_if(Vector, Pred), Vector.end());
317 return;
318 }
319
320 auto O = Vector.begin();
321 for (auto I = O, E = Vector.end(); I != E; ++I) {
322 if (Pred(*I)) {
323 // Erase from the map.
324 Map.erase(I->first);
325 continue;
326 }
327
328 if (I != O) {
329 // Move the value and update the index in the map.
330 *O = std::move(*I);
331 Map[O->first] = O - Vector.begin();
332 }
333 ++O;
334 }
335 // Erase trailing entries in the vector.
336 Vector.erase(O, Vector.end());
337}
338
339/// A MapVector that performs no allocations if smaller than a certain
340/// size.
341template <typename KeyT, typename ValueT, unsigned N>
343 : MapVector<KeyT, ValueT, DenseMap<KeyT, unsigned>,
344 SmallVector<std::pair<KeyT, ValueT>, N>, N> {};
345
346template <typename KeyT, typename ValueT,
347 typename MapType = DenseMap<KeyT, unsigned>,
349 unsigned N = 0>
350[[nodiscard]] size_t
352 return X.getMemorySize();
353}
354
355} // end namespace llvm
356
357#endif // LLVM_ADT_MAPVECTOR_H
SDValue Pred
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_ATTRIBUTE_WARN_UNUSED
Definition Compiler.h:240
This file defines the DenseMap class.
#define I(x, y, z)
Definition MD5.cpp:57
#define P(N)
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
Value * RHS
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:39
const std::pair< KeyT, ValueT > & back() const
Definition MapVector.h:87
size_type erase(const KeyT &Key)
Remove all elements with the key value Key.
Definition MapVector.h:234
void pop_back()
Remove the last element from the vector.
Definition MapVector.h:192
const_iterator begin() const
Definition MapVector.h:69
ValueT lookup(const KeyT &Key) const
Definition MapVector.h:111
ArrayRef< value_type > getArrayRef() const
Returns an array reference of the underlying vector.
Definition MapVector.h:57
iterator begin()
Definition MapVector.h:68
iterator find(const KeyT &Key)
Definition MapVector.h:157
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition MapVector.h:123
typename VectorType::const_iterator const_iterator
Definition MapVector.h:46
iterator end()
Definition MapVector.h:70
void reserve(size_type NumEntries)
Grow the MapVector so that it can contain at least NumEntries items before resizing again.
Definition MapVector.h:63
const_iterator end() const
Definition MapVector.h:71
std::pair< iterator, bool > try_emplace(const KeyT &Key, Ts &&...Args)
Definition MapVector.h:119
typename VectorType::iterator iterator
Definition MapVector.h:45
std::pair< iterator, bool > insert_or_assign(const KeyT &Key, V &&Val)
Definition MapVector.h:135
VectorType takeVector()
Clear the MapVector and return the underlying vector.
Definition MapVector.h:51
typename VectorType::reverse_iterator reverse_iterator
Definition MapVector.h:47
bool empty() const
Definition MapVector.h:80
reverse_iterator rend()
Definition MapVector.h:77
void swap(MapVector &RHS)
Definition MapVector.h:96
bool contains(const KeyT &Key) const
Definition MapVector.h:149
auto keys() const
Definition MapVector.h:106
void remove_if(Predicate Pred)
Remove the elements that match the predicate.
auto values() const
Definition MapVector.h:108
std::pair< iterator, bool > insert(std::pair< KeyT, ValueT > &&KV)
Definition MapVector.h:130
ValueT & operator[](const KeyT &Key)
Definition MapVector.h:101
const std::pair< KeyT, ValueT > & front() const
Definition MapVector.h:83
std::pair< KeyT, ValueT > & back()
Definition MapVector.h:86
std::pair< iterator, bool > insert_or_assign(KeyT &&Key, V &&Val)
Definition MapVector.h:142
const_reverse_iterator rend() const
Definition MapVector.h:78
ValueT & at(const KeyT &Key)
at - Return the entry for the specified key, or abort if no such entry exists.
Definition MapVector.h:177
const_iterator find(const KeyT &Key) const
Definition MapVector.h:166
const ValueT & at(const KeyT &Key) const
at - Return the entry for the specified key, or abort if no such entry exists.
Definition MapVector.h:185
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition MapVector.h:127
typename VectorType::size_type size_type
Definition MapVector.h:43
size_type size() const
Definition MapVector.h:59
VectorType::iterator erase(typename VectorType::iterator Iterator)
Remove the element given by Iterator.
Definition MapVector.h:211
size_type count(const KeyT &Key) const
Definition MapVector.h:153
const_reverse_iterator rbegin() const
Definition MapVector.h:74
size_t getMemorySize() const
Return the approximate size (in bytes) of the data structure.
Definition MapVector.h:252
reverse_iterator rbegin()
Definition MapVector.h:73
std::pair< KeyT, ValueT > & front()
Definition MapVector.h:82
typename VectorType::value_type value_type
Definition MapVector.h:42
typename VectorType::const_reverse_iterator const_reverse_iterator
Definition MapVector.h:48
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Base class of all SIMD vector types.
This is an optimization pass for GlobalISel generic memory operations.
BitVector::size_type capacity_in_bytes(const BitVector &X)
Definition BitVector.h:863
auto make_first_range(ContainerTy &&c)
Given a container of pairs, return a range over the first elements.
Definition STLExtras.h:1415
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
auto remove_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::remove_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1800
auto make_second_range(ContainerTy &&c)
Given a container of pairs, return a range over the second elements.
Definition STLExtras.h:1425
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1788
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
A MapVector that performs no allocations if smaller than a certain size.
Definition MapVector.h:344