LLVM 24.0.0git
ImmutableMap.h
Go to the documentation of this file.
1//===--- ImmutableMap.h - Immutable (functional) 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 ImmutableMap class.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_ADT_IMMUTABLEMAP_H
15#define LLVM_ADT_IMMUTABLEMAP_H
16
17#include "llvm/ADT/FoldingSet.h"
20#include <utility>
21
22namespace llvm {
23
24/// Traits class used by ImmutableMap. While both the first and second elements
25/// in a pair are used to generate profile information, only the first element
26/// (the key) is used by isEqual and isLess.
27template <typename T, typename S>
29 using value_type = const std::pair<T,S>;
30 using value_type_ref = const value_type&;
31 using key_type = const T;
32 using key_type_ref = const T&;
33 using data_type = const S;
34 using data_type_ref = const S&;
35
37 return V.first;
38 }
39
41 return V.second;
42 }
43
44 static inline bool isEqual(key_type_ref L, key_type_ref R) {
46 }
47 static inline bool isLess(key_type_ref L, key_type_ref R) {
49 }
50
51 static inline bool isDataEqual(data_type_ref L, data_type_ref R) {
53 }
54
59};
60
61template <typename KeyT, typename ValT,
62 typename ValInfo = ImutKeyValueInfo<KeyT, ValT>,
63 bool Canonicalize = true>
65public:
66 using value_type = typename ValInfo::value_type;
67 using value_type_ref = typename ValInfo::value_type_ref;
68 using key_type = typename ValInfo::key_type;
69 using key_type_ref = typename ValInfo::key_type_ref;
70 using data_type = typename ValInfo::data_type;
71 using data_type_ref = typename ValInfo::data_type_ref;
73
74protected:
76
77public:
78 /// Constructs a map from a pointer to a tree root. In general one
79 /// should use a Factory object to create maps instead of directly
80 /// invoking the constructor, but there are cases where make this
81 /// constructor public is useful.
82 explicit ImmutableMap(const TreeTy *R) : Root(const_cast<TreeTy *>(R)) {}
83
84 class Factory {
85 typename TreeTy::Factory F;
86
87 public:
88 Factory() = default;
89
91
92 Factory(const Factory &) = delete;
93 Factory &operator=(const Factory &) = delete;
94
95 ImmutableMap getEmptyMap() { return ImmutableMap(F.getEmptyTree()); }
96
99 TreeTy *T = F.add(Old.Root.get(), std::pair<key_type, data_type>(K, D));
100 if constexpr (Canonicalize)
101 return ImmutableMap(F.getCanonicalTree(T));
102 else
103 return ImmutableMap(T);
104 }
105
106 /// Merges \p A and \p B in a single traversal (see
107 /// ImutAVLFactory::mergeTrees), sharing subtrees the two maps do not
108 /// overlap. \p Combine(AElem, BElem) yields the stored element for a key;
109 /// \p KeepUnmatched governs keys unique to one side. \p SkipShared returns
110 /// a pointer-identical subtree unchanged in O(1); only pass true when the
111 /// merge is idempotent (Combine(a, a) == a, e.g. a lattice join). This is
112 /// more efficient than repeatedly adding \p B's entries to \p A when \p B
113 /// is large. Only valid for non-canonicalizing factories (the bulk path
114 /// does not canonicalize the nodes it creates). Does not short-circuit
115 /// equal/empty operands or reorder by size; callers wanting those apply
116 /// them first.
117 template <typename CombineFn>
119 CombineFn Combine, bool KeepUnmatched,
120 bool SkipShared = false) {
121 static_assert(!Canonicalize,
122 "mergeWith does not canonicalize the nodes it creates");
123 return ImmutableMap(F.mergeTrees(A.Root.get(), B.Root.get(), Combine,
124 KeepUnmatched, SkipShared));
125 }
126
128 TreeTy *T = F.remove(Old.Root.get(), K);
129 if constexpr (Canonicalize)
130 return ImmutableMap(F.getCanonicalTree(T));
131 else
132 return ImmutableMap(T);
133 }
134
135 typename TreeTy::Factory *getTreeFactory() const {
136 return const_cast<typename TreeTy::Factory *>(&F);
137 }
138 };
139
140 [[nodiscard]] bool contains(key_type_ref K) const {
141 return Root ? Root->contains(K) : false;
142 }
143
144 /// Compares two maps for equality. For a canonicalizing factory, maps with
145 /// equal contents share the same tree, so this is an O(1) pointer comparison
146 /// (like ImmutableList); only maps created by the same factory may be
147 /// compared. Otherwise it is a structural comparison.
148 [[nodiscard]] bool operator==(const ImmutableMap &RHS) const {
149 if constexpr (Canonicalize)
150 return Root == RHS.Root;
151 else
152 return Root && RHS.Root ? Root->isEqual(*RHS.Root.get())
153 : Root == RHS.Root;
154 }
155
156 [[nodiscard]] bool operator!=(const ImmutableMap &RHS) const {
157 if constexpr (Canonicalize)
158 return Root != RHS.Root;
159 else
160 return Root && RHS.Root ? Root->isNotEqual(*RHS.Root.get())
161 : Root != RHS.Root;
162 }
163
164 [[nodiscard]] TreeTy *getRoot() const {
165 if (Root) { Root->retain(); }
166 return Root.get();
167 }
168
169 [[nodiscard]] TreeTy *getRootWithoutRetain() const { return Root.get(); }
170
172 if (Root) Root->retain();
173 }
174
176 if (Root) Root->release();
177 }
178
179 [[nodiscard]] bool isEmpty() const { return !Root; }
180
181public:
182 //===--------------------------------------------------===//
183 // For testing.
184 //===--------------------------------------------------===//
185
186 void verify() const { if (Root) Root->verify(); }
187
188 //===--------------------------------------------------===//
189 // Iterators.
190 //===--------------------------------------------------===//
191
192 class iterator : public ImutAVLValueIterator<ImmutableMap> {
193 friend class ImmutableMap;
194
195 iterator() = default;
196 explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
197
198 public:
199 key_type_ref getKey() const { return (*this)->first; }
200 data_type_ref getData() const { return (*this)->second; }
201 };
202
203 [[nodiscard]] iterator begin() const { return iterator(Root.get()); }
204 [[nodiscard]] iterator end() const { return iterator(); }
205
206 [[nodiscard]] data_type *lookup(key_type_ref K) const {
207 if (Root) {
208 TreeTy* T = Root->find(K);
209 if (T) return &T->getValue().second;
210 }
211
212 return nullptr;
213 }
214
215 /// Returns the <key,value> pair in the ImmutableMap for which key is the
216 /// highest in the ordering of keys in the map. This method returns NULL if
217 /// the map is empty.
218 [[nodiscard]] value_type *getMaxElement() const {
219 return Root ? &(Root->getMaxElement()->getValue()) : nullptr;
220 }
221
222 //===--------------------------------------------------===//
223 // Utility methods.
224 //===--------------------------------------------------===//
225
226 [[nodiscard]] unsigned getHeight() const {
227 return Root ? Root->getHeight() : 0;
228 }
229
230 static inline void Profile(FoldingSetNodeID& ID, const ImmutableMap& M) {
231 ID.AddPointer(M.Root.get());
232 }
233
234 inline void Profile(FoldingSetNodeID& ID) const {
235 return Profile(ID,*this);
236 }
237};
238
239// NOTE: This will possibly become the new implementation of ImmutableMap some day.
240template <typename KeyT, typename ValT,
241typename ValInfo = ImutKeyValueInfo<KeyT,ValT>>
243public:
244 using value_type = typename ValInfo::value_type;
245 using value_type_ref = typename ValInfo::value_type_ref;
246 using key_type = typename ValInfo::key_type;
247 using key_type_ref = typename ValInfo::key_type_ref;
248 using data_type = typename ValInfo::data_type;
249 using data_type_ref = typename ValInfo::data_type_ref;
251 using FactoryTy = typename TreeTy::Factory;
252
253protected:
256
257public:
258 /// Constructs a map from a pointer to a tree root. In general one
259 /// should use a Factory object to create maps instead of directly
260 /// invoking the constructor, but there are cases where make this
261 /// constructor public is useful.
263 : Root(const_cast<TreeTy *>(R)), Factory(F) {}
264
267 : Root(X.getRootWithoutRetain()), Factory(F.getTreeFactory()) {}
268
270 return ImmutableMapRef(nullptr, F);
271 }
272
274 if (Root) Root->retain();
275 }
276
278 if (Root) Root->release();
279 }
280
282 TreeTy *NewT =
283 Factory->add(Root.get(), std::pair<key_type, data_type>(K, D));
284 return ImmutableMapRef(NewT, Factory);
285 }
286
288 TreeTy *NewT = Factory->remove(Root.get(), K);
289 return ImmutableMapRef(NewT, Factory);
290 }
291
292 [[nodiscard]] bool contains(key_type_ref K) const {
293 return Root ? Root->contains(K) : false;
294 }
295
297 return ImmutableMap<KeyT, ValT>(Factory->getCanonicalTree(Root.get()));
298 }
299
300 [[nodiscard]] bool operator==(const ImmutableMapRef &RHS) const {
301 return Root && RHS.Root ? Root->isEqual(*RHS.Root.get()) : Root == RHS.Root;
302 }
303
304 [[nodiscard]] bool operator!=(const ImmutableMapRef &RHS) const {
305 return Root && RHS.Root ? Root->isNotEqual(*RHS.Root.get())
306 : Root != RHS.Root;
307 }
308
309 [[nodiscard]] bool isEmpty() const { return !Root; }
310
311 //===--------------------------------------------------===//
312 // For testing.
313 //===--------------------------------------------------===//
314
315 void verify() const {
316 if (Root)
317 Root->verify();
318 }
319
320 //===--------------------------------------------------===//
321 // Iterators.
322 //===--------------------------------------------------===//
323
324 class iterator : public ImutAVLValueIterator<ImmutableMapRef> {
325 friend class ImmutableMapRef;
326
327 iterator() = default;
328 explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
329
330 public:
331 key_type_ref getKey() const { return (*this)->first; }
332 data_type_ref getData() const { return (*this)->second; }
333 };
334
335 [[nodiscard]] iterator begin() const { return iterator(Root.get()); }
336 [[nodiscard]] iterator end() const { return iterator(); }
337
338 [[nodiscard]] data_type *lookup(key_type_ref K) const {
339 if (Root) {
340 TreeTy* T = Root->find(K);
341 if (T) return &T->getValue().second;
342 }
343
344 return nullptr;
345 }
346
347 /// Returns the <key,value> pair in the ImmutableMap for which key is the
348 /// highest in the ordering of keys in the map. This method returns NULL if
349 /// the map is empty.
350 [[nodiscard]] value_type *getMaxElement() const {
351 return Root ? &(Root->getMaxElement()->getValue()) : nullptr;
352 }
353
354 //===--------------------------------------------------===//
355 // Utility methods.
356 //===--------------------------------------------------===//
357
358 [[nodiscard]] unsigned getHeight() const {
359 return Root ? Root->getHeight() : 0;
360 }
361
362 static inline void Profile(FoldingSetNodeID &ID, const ImmutableMapRef &M) {
363 ID.AddPointer(M.Root.get());
364 }
365
366 inline void Profile(FoldingSetNodeID &ID) const { return Profile(ID, *this); }
367};
368
369} // end namespace llvm
370
371#endif // LLVM_ADT_IMMUTABLEMAP_H
AMDGPU Uniform Intrinsic Combine
This file defines the BumpPtrAllocator interface.
#define X(NUM, ENUM, NAME)
Definition ELF.h:856
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines a hash set that can be used to remove duplication of nodes in a graph.
This file defines the ImutAVLTree and ImmutableSet classes.
static constexpr Value * getValue(Ty &ValueOrUse)
#define F(x, y, z)
Definition MD5.cpp:54
Load MIR Sample Profile
#define T
Value * RHS
This class is used to gather all the unique data bits of a node.
Definition FoldingSet.h:208
key_type_ref getKey() const
data_type_ref getData() const
unsigned getHeight() const
ImmutableMap< KeyT, ValT > asImmutableMap() const
static ImmutableMapRef getEmptyMap(FactoryTy *F)
void Profile(FoldingSetNodeID &ID) const
bool operator!=(const ImmutableMapRef &RHS) const
bool contains(key_type_ref K) const
static void Profile(FoldingSetNodeID &ID, const ImmutableMapRef &M)
typename ValInfo::data_type data_type
typename ValInfo::data_type_ref data_type_ref
typename ValInfo::key_type key_type
IntrusiveRefCntPtr< TreeTy > Root
ImutAVLTree< ValInfo > TreeTy
typename ValInfo::value_type_ref value_type_ref
bool operator==(const ImmutableMapRef &RHS) const
ImmutableMapRef remove(key_type_ref K) const
typename ValInfo::key_type_ref key_type_ref
value_type * getMaxElement() const
Returns the <key,value> pair in the ImmutableMap for which key is the highest in the ordering of keys...
ImmutableMapRef add(key_type_ref K, data_type_ref D) const
typename ValInfo::value_type value_type
iterator begin() const
ImmutableMapRef(const TreeTy *R, FactoryTy *F)
Constructs a map from a pointer to a tree root.
data_type * lookup(key_type_ref K) const
iterator end() const
ImmutableMapRef(const ImmutableMap< KeyT, ValT > &X, typename ImmutableMap< KeyT, ValT >::Factory &F)
typename TreeTy::Factory FactoryTy
TreeTy::Factory * getTreeFactory() const
ImmutableMap remove(ImmutableMap Old, key_type_ref K)
Factory(BumpPtrAllocator &Alloc)
Factory & operator=(const Factory &)=delete
ImmutableMap mergeWith(ImmutableMap A, ImmutableMap B, CombineFn Combine, bool KeepUnmatched, bool SkipShared=false)
Merges A and B in a single traversal (see ImutAVLFactory::mergeTrees), sharing subtrees the two maps ...
ImmutableMap add(ImmutableMap Old, key_type_ref K, data_type_ref D)
Factory(const Factory &)=delete
key_type_ref getKey() const
data_type_ref getData() const
typename ValInfo::data_type_ref data_type_ref
TreeTy * getRootWithoutRetain() const
bool isEmpty() const
iterator begin() const
typename ValInfo::key_type_ref key_type_ref
TreeTy * getRoot() const
typename ValInfo::value_type_ref value_type_ref
iterator end() const
value_type * getMaxElement() const
Returns the <key,value> pair in the ImmutableMap for which key is the highest in the ordering of keys...
void verify() const
typename ValInfo::key_type key_type
typename ValInfo::value_type value_type
typename ValInfo::data_type data_type
void Profile(FoldingSetNodeID &ID) const
bool operator!=(const ImmutableMap &RHS) const
ImmutableMap(const TreeTy *R)
Constructs a map from a pointer to a tree root.
bool contains(key_type_ref K) const
unsigned getHeight() const
data_type * lookup(key_type_ref K) const
IntrusiveRefCntPtr< TreeTy > Root
bool operator==(const ImmutableMap &RHS) const
Compares two maps for equality.
ImutAVLTree< ValInfo, Canonicalize > TreeTy
static void Profile(FoldingSetNodeID &ID, const ImmutableMap &M)
ImutAVLFactory< ValInfo, Canonicalize > Factory
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:390
static bool isLess(key_type_ref LHS, key_type_ref RHS)
static bool isEqual(key_type_ref LHS, key_type_ref RHS)
Traits class used by ImmutableMap.
const value_type & value_type_ref
static void Profile(FoldingSetNodeID &ID, value_type_ref V)
static bool isLess(key_type_ref L, key_type_ref R)
static key_type_ref KeyOfValue(value_type_ref V)
const std::pair< T, S > value_type
static data_type_ref DataOfValue(value_type_ref V)
static bool isDataEqual(data_type_ref L, data_type_ref R)
static bool isEqual(key_type_ref L, key_type_ref R)
static void Profile(FoldingSetNodeID &ID, value_type_ref X)