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"
21#include <utility>
22
23namespace llvm {
24
25/// Traits class used by ImmutableMap. While both the first and second elements
26/// in a pair are used to generate profile information, only the first element
27/// (the key) is used by isEqual and isLess.
28template <typename T, typename S>
30 using value_type = const std::pair<T,S>;
31 using value_type_ref = const value_type&;
32 using key_type = const T;
33 using key_type_ref = const T&;
34 using data_type = const S;
35 using data_type_ref = const S&;
36
38 return V.first;
39 }
40
42 return V.second;
43 }
44
45 static inline bool isEqual(key_type_ref L, key_type_ref R) {
47 }
48 static inline bool isLess(key_type_ref L, key_type_ref R) {
50 }
51
52 static inline bool isDataEqual(data_type_ref L, data_type_ref R) {
54 }
55
56 static inline void Profile(FoldingSetNodeID& ID, value_type_ref V) {
59 }
60};
61
62template <typename KeyT, typename ValT,
63 typename ValInfo = ImutKeyValueInfo<KeyT, ValT>,
64 bool Canonicalize = true>
66public:
67 using value_type = typename ValInfo::value_type;
68 using value_type_ref = typename ValInfo::value_type_ref;
69 using key_type = typename ValInfo::key_type;
70 using key_type_ref = typename ValInfo::key_type_ref;
71 using data_type = typename ValInfo::data_type;
72 using data_type_ref = typename ValInfo::data_type_ref;
74
75protected:
77
78public:
79 /// Constructs a map from a pointer to a tree root. In general one
80 /// should use a Factory object to create maps instead of directly
81 /// invoking the constructor, but there are cases where make this
82 /// constructor public is useful.
83 explicit ImmutableMap(const TreeTy *R) : Root(const_cast<TreeTy *>(R)) {}
84
85 class Factory {
86 typename TreeTy::Factory F;
87
88 public:
89 Factory() = default;
90
92
93 Factory(const Factory &) = delete;
94 Factory &operator=(const Factory &) = delete;
95
96 ImmutableMap getEmptyMap() { return ImmutableMap(F.getEmptyTree()); }
97
100 TreeTy *T = F.add(Old.Root.get(), std::pair<key_type, data_type>(K, D));
101 if constexpr (Canonicalize)
102 return ImmutableMap(F.getCanonicalTree(T));
103 else
104 return ImmutableMap(T);
105 }
106
107 /// Merges \p A and \p B in a single traversal (see
108 /// ImutAVLFactory::mergeTrees), sharing subtrees the two maps do not
109 /// overlap. \p Combine(AElem, BElem) yields the stored element for a key;
110 /// \p KeepUnmatched governs keys unique to one side. \p SkipShared returns
111 /// a pointer-identical subtree unchanged in O(1); only pass true when the
112 /// merge is idempotent (Combine(a, a) == a, e.g. a lattice join). This is
113 /// more efficient than repeatedly adding \p B's entries to \p A when \p B
114 /// is large. Only valid for non-canonicalizing factories (the bulk path
115 /// does not canonicalize the nodes it creates). Does not short-circuit
116 /// equal/empty operands or reorder by size; callers wanting those apply
117 /// them first.
118 template <typename CombineFn>
120 CombineFn Combine, bool KeepUnmatched,
121 bool SkipShared = false) {
122 static_assert(!Canonicalize,
123 "mergeWith does not canonicalize the nodes it creates");
124 return ImmutableMap(F.mergeTrees(A.Root.get(), B.Root.get(), Combine,
125 KeepUnmatched, SkipShared));
126 }
127
129 TreeTy *T = F.remove(Old.Root.get(), K);
130 if constexpr (Canonicalize)
131 return ImmutableMap(F.getCanonicalTree(T));
132 else
133 return ImmutableMap(T);
134 }
135
136 typename TreeTy::Factory *getTreeFactory() const {
137 return const_cast<typename TreeTy::Factory *>(&F);
138 }
139 };
140
141 [[nodiscard]] bool contains(key_type_ref K) const {
142 return Root ? Root->contains(K) : false;
143 }
144
145 /// Compares two maps for equality. For a canonicalizing factory, maps with
146 /// equal contents share the same tree, so this is an O(1) pointer comparison
147 /// (like ImmutableList); only maps created by the same factory may be
148 /// compared. Otherwise it is a structural comparison.
149 [[nodiscard]] bool operator==(const ImmutableMap &RHS) const {
150 if constexpr (Canonicalize)
151 return Root == RHS.Root;
152 else
153 return Root && RHS.Root ? Root->isEqual(*RHS.Root.get())
154 : Root == RHS.Root;
155 }
156
157 [[nodiscard]] bool operator!=(const ImmutableMap &RHS) const {
158 if constexpr (Canonicalize)
159 return Root != RHS.Root;
160 else
161 return Root && RHS.Root ? Root->isNotEqual(*RHS.Root.get())
162 : Root != RHS.Root;
163 }
164
165 [[nodiscard]] TreeTy *getRoot() const {
166 if (Root) { Root->retain(); }
167 return Root.get();
168 }
169
170 [[nodiscard]] TreeTy *getRootWithoutRetain() const { return Root.get(); }
171
173 if (Root) Root->retain();
174 }
175
177 if (Root) Root->release();
178 }
179
180 [[nodiscard]] bool isEmpty() const { return !Root; }
181
182public:
183 //===--------------------------------------------------===//
184 // For testing.
185 //===--------------------------------------------------===//
186
187 void verify() const { if (Root) Root->verify(); }
188
189 //===--------------------------------------------------===//
190 // Iterators.
191 //===--------------------------------------------------===//
192
193 class iterator : public ImutAVLValueIterator<ImmutableMap> {
194 friend class ImmutableMap;
195
196 iterator() = default;
197 explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
198
199 public:
200 key_type_ref getKey() const { return (*this)->first; }
201 data_type_ref getData() const { return (*this)->second; }
202 };
203
204 [[nodiscard]] iterator begin() const { return iterator(Root.get()); }
205 [[nodiscard]] iterator end() const { return iterator(); }
206
207 [[nodiscard]] data_type *lookup(key_type_ref K) const {
208 if (Root) {
209 TreeTy* T = Root->find(K);
210 if (T) return &T->getValue().second;
211 }
212
213 return nullptr;
214 }
215
216 /// Returns the <key,value> pair in the ImmutableMap for which key is the
217 /// highest in the ordering of keys in the map. This method returns NULL if
218 /// the map is empty.
219 [[nodiscard]] value_type *getMaxElement() const {
220 return Root ? &(Root->getMaxElement()->getValue()) : nullptr;
221 }
222
223 //===--------------------------------------------------===//
224 // Utility methods.
225 //===--------------------------------------------------===//
226
227 [[nodiscard]] unsigned getHeight() const {
228 return Root ? Root->getHeight() : 0;
229 }
230
231 static inline void Profile(FoldingSetNodeID& ID, const ImmutableMap& M) {
232 ID.AddPointer(M.Root.get());
233 }
234
235 inline void Profile(FoldingSetNodeID& ID) const {
236 return Profile(ID,*this);
237 }
238};
239
240// NOTE: This will possibly become the new implementation of ImmutableMap some day.
241template <typename KeyT, typename ValT,
242typename ValInfo = ImutKeyValueInfo<KeyT,ValT>>
244public:
245 using value_type = typename ValInfo::value_type;
246 using value_type_ref = typename ValInfo::value_type_ref;
247 using key_type = typename ValInfo::key_type;
248 using key_type_ref = typename ValInfo::key_type_ref;
249 using data_type = typename ValInfo::data_type;
250 using data_type_ref = typename ValInfo::data_type_ref;
252 using FactoryTy = typename TreeTy::Factory;
253
254protected:
257
258public:
259 /// Constructs a map from a pointer to a tree root. In general one
260 /// should use a Factory object to create maps instead of directly
261 /// invoking the constructor, but there are cases where make this
262 /// constructor public is useful.
264 : Root(const_cast<TreeTy *>(R)), Factory(F) {}
265
268 : Root(X.getRootWithoutRetain()), Factory(F.getTreeFactory()) {}
269
271 return ImmutableMapRef(nullptr, F);
272 }
273
275 if (Root) Root->retain();
276 }
277
279 if (Root) Root->release();
280 }
281
283 TreeTy *NewT =
284 Factory->add(Root.get(), std::pair<key_type, data_type>(K, D));
285 return ImmutableMapRef(NewT, Factory);
286 }
287
289 TreeTy *NewT = Factory->remove(Root.get(), K);
290 return ImmutableMapRef(NewT, Factory);
291 }
292
293 [[nodiscard]] bool contains(key_type_ref K) const {
294 return Root ? Root->contains(K) : false;
295 }
296
298 return ImmutableMap<KeyT, ValT>(Factory->getCanonicalTree(Root.get()));
299 }
300
301 [[nodiscard]] bool operator==(const ImmutableMapRef &RHS) const {
302 return Root && RHS.Root ? Root->isEqual(*RHS.Root.get()) : Root == RHS.Root;
303 }
304
305 [[nodiscard]] bool operator!=(const ImmutableMapRef &RHS) const {
306 return Root && RHS.Root ? Root->isNotEqual(*RHS.Root.get())
307 : Root != RHS.Root;
308 }
309
310 [[nodiscard]] bool isEmpty() const { return !Root; }
311
312 //===--------------------------------------------------===//
313 // For testing.
314 //===--------------------------------------------------===//
315
316 void verify() const {
317 if (Root)
318 Root->verify();
319 }
320
321 //===--------------------------------------------------===//
322 // Iterators.
323 //===--------------------------------------------------===//
324
325 class iterator : public ImutAVLValueIterator<ImmutableMapRef> {
326 friend class ImmutableMapRef;
327
328 iterator() = default;
329 explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
330
331 public:
332 key_type_ref getKey() const { return (*this)->first; }
333 data_type_ref getData() const { return (*this)->second; }
334 };
335
336 [[nodiscard]] iterator begin() const { return iterator(Root.get()); }
337 [[nodiscard]] iterator end() const { return iterator(); }
338
339 [[nodiscard]] data_type *lookup(key_type_ref K) const {
340 if (Root) {
341 TreeTy* T = Root->find(K);
342 if (T) return &T->getValue().second;
343 }
344
345 return nullptr;
346 }
347
348 /// Returns the <key,value> pair in the ImmutableMap for which key is the
349 /// highest in the ordering of keys in the map. This method returns NULL if
350 /// the map is empty.
351 [[nodiscard]] value_type *getMaxElement() const {
352 return Root ? &(Root->getMaxElement()->getValue()) : nullptr;
353 }
354
355 //===--------------------------------------------------===//
356 // Utility methods.
357 //===--------------------------------------------------===//
358
359 [[nodiscard]] unsigned getHeight() const {
360 return Root ? Root->getHeight() : 0;
361 }
362
363 static inline void Profile(FoldingSetNodeID &ID, const ImmutableMapRef &M) {
364 ID.AddPointer(M.Root.get());
365 }
366
367 inline void Profile(FoldingSetNodeID &ID) const { return Profile(ID, *this); }
368};
369
370} // end namespace llvm
371
372#endif // LLVM_ADT_IMMUTABLEMAP_H
AMDGPU Uniform Intrinsic Combine
This file defines the BumpPtrAllocator interface.
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
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")
#define LLVM_ATTRIBUTE_WARN_UNUSED
Definition Compiler.h:240
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:162
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...
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:391
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)