1 //===--- ImmutableMap.h - Immutable (functional) map interface --*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the ImmutableMap class.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_ADT_IMMUTABLEMAP_H
14 #define LLVM_ADT_IMMUTABLEMAP_H
16 #include "llvm/ADT/FoldingSet.h"
17 #include "llvm/ADT/ImmutableSet.h"
18 #include "llvm/Support/Allocator.h"
23 /// ImutKeyValueInfo -Traits class used by ImmutableMap. While both the first
24 /// and second elements in a pair are used to generate profile information,
25 /// only the first element (the key) is used by isEqual and isLess.
26 template <typename T
, typename S
>
27 struct ImutKeyValueInfo
{
28 using value_type
= const std::pair
<T
,S
>;
29 using value_type_ref
= const value_type
&;
30 using key_type
= const T
;
31 using key_type_ref
= const T
&;
32 using data_type
= const S
;
33 using data_type_ref
= const S
&;
35 static inline key_type_ref
KeyOfValue(value_type_ref V
) {
39 static inline data_type_ref
DataOfValue(value_type_ref V
) {
43 static inline bool isEqual(key_type_ref L
, key_type_ref R
) {
44 return ImutContainerInfo
<T
>::isEqual(L
,R
);
46 static inline bool isLess(key_type_ref L
, key_type_ref R
) {
47 return ImutContainerInfo
<T
>::isLess(L
,R
);
50 static inline bool isDataEqual(data_type_ref L
, data_type_ref R
) {
51 return ImutContainerInfo
<S
>::isEqual(L
,R
);
54 static inline void Profile(FoldingSetNodeID
& ID
, value_type_ref V
) {
55 ImutContainerInfo
<T
>::Profile(ID
, V
.first
);
56 ImutContainerInfo
<S
>::Profile(ID
, V
.second
);
60 template <typename KeyT
, typename ValT
,
61 typename ValInfo
= ImutKeyValueInfo
<KeyT
,ValT
>>
64 using value_type
= typename
ValInfo::value_type
;
65 using value_type_ref
= typename
ValInfo::value_type_ref
;
66 using key_type
= typename
ValInfo::key_type
;
67 using key_type_ref
= typename
ValInfo::key_type_ref
;
68 using data_type
= typename
ValInfo::data_type
;
69 using data_type_ref
= typename
ValInfo::data_type_ref
;
70 using TreeTy
= ImutAVLTree
<ValInfo
>;
76 /// Constructs a map from a pointer to a tree root. In general one
77 /// should use a Factory object to create maps instead of directly
78 /// invoking the constructor, but there are cases where make this
79 /// constructor public is useful.
80 explicit ImmutableMap(const TreeTy
* R
) : Root(const_cast<TreeTy
*>(R
)) {
81 if (Root
) { Root
->retain(); }
84 ImmutableMap(const ImmutableMap
&X
) : Root(X
.Root
) {
85 if (Root
) { Root
->retain(); }
89 if (Root
) { Root
->release(); }
92 ImmutableMap
&operator=(const ImmutableMap
&X
) {
94 if (X
.Root
) { X
.Root
->retain(); }
95 if (Root
) { Root
->release(); }
102 typename
TreeTy::Factory F
;
103 const bool Canonicalize
;
106 Factory(bool canonicalize
= true) : Canonicalize(canonicalize
) {}
108 Factory(BumpPtrAllocator
&Alloc
, bool canonicalize
= true)
109 : F(Alloc
), Canonicalize(canonicalize
) {}
111 Factory(const Factory
&) = delete;
112 Factory
&operator=(const Factory
&) = delete;
114 ImmutableMap
getEmptyMap() { return ImmutableMap(F
.getEmptyTree()); }
116 LLVM_NODISCARD ImmutableMap
add(ImmutableMap Old
, key_type_ref K
,
118 TreeTy
*T
= F
.add(Old
.Root
, std::pair
<key_type
,data_type
>(K
,D
));
119 return ImmutableMap(Canonicalize
? F
.getCanonicalTree(T
): T
);
122 LLVM_NODISCARD ImmutableMap
remove(ImmutableMap Old
, key_type_ref K
) {
123 TreeTy
*T
= F
.remove(Old
.Root
,K
);
124 return ImmutableMap(Canonicalize
? F
.getCanonicalTree(T
): T
);
127 typename
TreeTy::Factory
*getTreeFactory() const {
128 return const_cast<typename
TreeTy::Factory
*>(&F
);
132 bool contains(key_type_ref K
) const {
133 return Root
? Root
->contains(K
) : false;
136 bool operator==(const ImmutableMap
&RHS
) const {
137 return Root
&& RHS
.Root
? Root
->isEqual(*RHS
.Root
) : Root
== RHS
.Root
;
140 bool operator!=(const ImmutableMap
&RHS
) const {
141 return Root
&& RHS
.Root
? Root
->isNotEqual(*RHS
.Root
) : Root
!= RHS
.Root
;
144 TreeTy
*getRoot() const {
145 if (Root
) { Root
->retain(); }
149 TreeTy
*getRootWithoutRetain() const { return Root
; }
151 void manualRetain() {
152 if (Root
) Root
->retain();
155 void manualRelease() {
156 if (Root
) Root
->release();
159 bool isEmpty() const { return !Root
; }
161 //===--------------------------------------------------===//
162 // Foreach - A limited form of map iteration.
163 //===--------------------------------------------------===//
166 template <typename Callback
>
170 void operator()(value_type_ref V
) { C(V
.first
,V
.second
); }
173 template <typename Callback
>
174 struct CBWrapperRef
{
177 CBWrapperRef(Callback
& c
) : C(c
) {}
179 void operator()(value_type_ref V
) { C(V
.first
,V
.second
); }
183 template <typename Callback
>
184 void foreach(Callback
& C
) {
186 CBWrapperRef
<Callback
> CB(C
);
191 template <typename Callback
>
194 CBWrapper
<Callback
> CB
;
199 //===--------------------------------------------------===//
201 //===--------------------------------------------------===//
203 void verify() const { if (Root
) Root
->verify(); }
205 //===--------------------------------------------------===//
207 //===--------------------------------------------------===//
209 class iterator
: public ImutAVLValueIterator
<ImmutableMap
> {
210 friend class ImmutableMap
;
212 iterator() = default;
213 explicit iterator(TreeTy
*Tree
) : iterator::ImutAVLValueIterator(Tree
) {}
216 key_type_ref
getKey() const { return (*this)->first
; }
217 data_type_ref
getData() const { return (*this)->second
; }
220 iterator
begin() const { return iterator(Root
); }
221 iterator
end() const { return iterator(); }
223 data_type
* lookup(key_type_ref K
) const {
225 TreeTy
* T
= Root
->find(K
);
226 if (T
) return &T
->getValue().second
;
232 /// getMaxElement - Returns the <key,value> pair in the ImmutableMap for
233 /// which key is the highest in the ordering of keys in the map. This
234 /// method returns NULL if the map is empty.
235 value_type
* getMaxElement() const {
236 return Root
? &(Root
->getMaxElement()->getValue()) : nullptr;
239 //===--------------------------------------------------===//
241 //===--------------------------------------------------===//
243 unsigned getHeight() const { return Root
? Root
->getHeight() : 0; }
245 static inline void Profile(FoldingSetNodeID
& ID
, const ImmutableMap
& M
) {
246 ID
.AddPointer(M
.Root
);
249 inline void Profile(FoldingSetNodeID
& ID
) const {
250 return Profile(ID
,*this);
254 // NOTE: This will possibly become the new implementation of ImmutableMap some day.
255 template <typename KeyT
, typename ValT
,
256 typename ValInfo
= ImutKeyValueInfo
<KeyT
,ValT
>>
257 class ImmutableMapRef
{
259 using value_type
= typename
ValInfo::value_type
;
260 using value_type_ref
= typename
ValInfo::value_type_ref
;
261 using key_type
= typename
ValInfo::key_type
;
262 using key_type_ref
= typename
ValInfo::key_type_ref
;
263 using data_type
= typename
ValInfo::data_type
;
264 using data_type_ref
= typename
ValInfo::data_type_ref
;
265 using TreeTy
= ImutAVLTree
<ValInfo
>;
266 using FactoryTy
= typename
TreeTy::Factory
;
273 /// Constructs a map from a pointer to a tree root. In general one
274 /// should use a Factory object to create maps instead of directly
275 /// invoking the constructor, but there are cases where make this
276 /// constructor public is useful.
277 explicit ImmutableMapRef(const TreeTy
*R
, FactoryTy
*F
)
278 : Root(const_cast<TreeTy
*>(R
)), Factory(F
) {
284 explicit ImmutableMapRef(const ImmutableMap
<KeyT
, ValT
> &X
,
285 typename ImmutableMap
<KeyT
, ValT
>::Factory
&F
)
286 : Root(X
.getRootWithoutRetain()),
287 Factory(F
.getTreeFactory()) {
288 if (Root
) { Root
->retain(); }
291 ImmutableMapRef(const ImmutableMapRef
&X
) : Root(X
.Root
), Factory(X
.Factory
) {
302 ImmutableMapRef
&operator=(const ImmutableMapRef
&X
) {
303 if (Root
!= X
.Root
) {
316 static inline ImmutableMapRef
getEmptyMap(FactoryTy
*F
) {
317 return ImmutableMapRef(0, F
);
320 void manualRetain() {
321 if (Root
) Root
->retain();
324 void manualRelease() {
325 if (Root
) Root
->release();
328 ImmutableMapRef
add(key_type_ref K
, data_type_ref D
) const {
329 TreeTy
*NewT
= Factory
->add(Root
, std::pair
<key_type
, data_type
>(K
, D
));
330 return ImmutableMapRef(NewT
, Factory
);
333 ImmutableMapRef
remove(key_type_ref K
) const {
334 TreeTy
*NewT
= Factory
->remove(Root
, K
);
335 return ImmutableMapRef(NewT
, Factory
);
338 bool contains(key_type_ref K
) const {
339 return Root
? Root
->contains(K
) : false;
342 ImmutableMap
<KeyT
, ValT
> asImmutableMap() const {
343 return ImmutableMap
<KeyT
, ValT
>(Factory
->getCanonicalTree(Root
));
346 bool operator==(const ImmutableMapRef
&RHS
) const {
347 return Root
&& RHS
.Root
? Root
->isEqual(*RHS
.Root
) : Root
== RHS
.Root
;
350 bool operator!=(const ImmutableMapRef
&RHS
) const {
351 return Root
&& RHS
.Root
? Root
->isNotEqual(*RHS
.Root
) : Root
!= RHS
.Root
;
354 bool isEmpty() const { return !Root
; }
356 //===--------------------------------------------------===//
358 //===--------------------------------------------------===//
360 void verify() const {
365 //===--------------------------------------------------===//
367 //===--------------------------------------------------===//
369 class iterator
: public ImutAVLValueIterator
<ImmutableMapRef
> {
370 friend class ImmutableMapRef
;
372 iterator() = default;
373 explicit iterator(TreeTy
*Tree
) : iterator::ImutAVLValueIterator(Tree
) {}
376 key_type_ref
getKey() const { return (*this)->first
; }
377 data_type_ref
getData() const { return (*this)->second
; }
380 iterator
begin() const { return iterator(Root
); }
381 iterator
end() const { return iterator(); }
383 data_type
*lookup(key_type_ref K
) const {
385 TreeTy
* T
= Root
->find(K
);
386 if (T
) return &T
->getValue().second
;
392 /// getMaxElement - Returns the <key,value> pair in the ImmutableMap for
393 /// which key is the highest in the ordering of keys in the map. This
394 /// method returns NULL if the map is empty.
395 value_type
* getMaxElement() const {
396 return Root
? &(Root
->getMaxElement()->getValue()) : 0;
399 //===--------------------------------------------------===//
401 //===--------------------------------------------------===//
403 unsigned getHeight() const { return Root
? Root
->getHeight() : 0; }
405 static inline void Profile(FoldingSetNodeID
&ID
, const ImmutableMapRef
&M
) {
406 ID
.AddPointer(M
.Root
);
409 inline void Profile(FoldingSetNodeID
&ID
) const { return Profile(ID
, *this); }
412 } // end namespace llvm
414 #endif // LLVM_ADT_IMMUTABLEMAP_H