1//===--- ImmutableMap.h - Immutable (functional) map interface --*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
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"
18#include "llvm/ADT/ImmutableSet.h"
19#include "llvm/Support/Allocator.h"
20#include <utility>
21
22namespace llvm {
23
24/// ImutKeyValueInfo -Traits class used by ImmutableMap.  While both the first
25/// and second elements in a pair are used to generate profile information,
26/// only the first element (the key) is used by isEqual and isLess.
27template <typename T, typename S>
28struct ImutKeyValueInfo {
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
36  static inline key_type_ref KeyOfValue(value_type_ref V) {
37    return V.first;
38  }
39
40  static inline data_type_ref DataOfValue(value_type_ref V) {
41    return V.second;
42  }
43
44  static inline bool isEqual(key_type_ref L, key_type_ref R) {
45    return ImutContainerInfo<T>::isEqual(L,R);
46  }
47  static inline bool isLess(key_type_ref L, key_type_ref R) {
48    return ImutContainerInfo<T>::isLess(L,R);
49  }
50
51  static inline bool isDataEqual(data_type_ref L, data_type_ref R) {
52    return ImutContainerInfo<S>::isEqual(L,R);
53  }
54
55  static inline void Profile(FoldingSetNodeID& ID, value_type_ref V) {
56    ImutContainerInfo<T>::Profile(ID, V.first);
57    ImutContainerInfo<S>::Profile(ID, V.second);
58  }
59};
60
61template <typename KeyT, typename ValT,
62          typename ValInfo = ImutKeyValueInfo<KeyT,ValT>>
63class ImmutableMap {
64public:
65  using value_type = typename ValInfo::value_type;
66  using value_type_ref = typename ValInfo::value_type_ref;
67  using key_type = typename ValInfo::key_type;
68  using key_type_ref = typename ValInfo::key_type_ref;
69  using data_type = typename ValInfo::data_type;
70  using data_type_ref = typename ValInfo::data_type_ref;
71  using TreeTy = ImutAVLTree<ValInfo>;
72
73protected:
74  TreeTy* Root;
75
76public:
77  /// Constructs a map from a pointer to a tree root.  In general one
78  /// should use a Factory object to create maps instead of directly
79  /// invoking the constructor, but there are cases where make this
80  /// constructor public is useful.
81  explicit ImmutableMap(const TreeTy* R) : Root(const_cast<TreeTy*>(R)) {
82    if (Root) { Root->retain(); }
83  }
84
85  ImmutableMap(const ImmutableMap &X) : Root(X.Root) {
86    if (Root) { Root->retain(); }
87  }
88
89  ~ImmutableMap() {
90    if (Root) { Root->release(); }
91  }
92
93  ImmutableMap &operator=(const ImmutableMap &X) {
94    if (Root != X.Root) {
95      if (X.Root) { X.Root->retain(); }
96      if (Root) { Root->release(); }
97      Root = X.Root;
98    }
99    return *this;
100  }
101
102  class Factory {
103    typename TreeTy::Factory F;
104    const bool Canonicalize;
105
106  public:
107    Factory(bool canonicalize = true) : Canonicalize(canonicalize) {}
108
109    Factory(BumpPtrAllocator &Alloc, bool canonicalize = true)
110        : F(Alloc), Canonicalize(canonicalize) {}
111
112    Factory(const Factory &) = delete;
113    Factory &operator=(const Factory &) = delete;
114
115    ImmutableMap getEmptyMap() { return ImmutableMap(F.getEmptyTree()); }
116
117    ImmutableMap add(ImmutableMap Old, key_type_ref K, data_type_ref D) {
118      TreeTy *T = F.add(Old.Root, std::pair<key_type,data_type>(K,D));
119      return ImmutableMap(Canonicalize ? F.getCanonicalTree(T): T);
120    }
121
122    ImmutableMap remove(ImmutableMap Old, key_type_ref K) {
123      TreeTy *T = F.remove(Old.Root,K);
124      return ImmutableMap(Canonicalize ? F.getCanonicalTree(T): T);
125    }
126
127    typename TreeTy::Factory *getTreeFactory() const {
128      return const_cast<typename TreeTy::Factory *>(&F);
129    }
130  };
131
132  bool contains(key_type_ref K) const {
133    return Root ? Root->contains(K) : false;
134  }
135
136  bool operator==(const ImmutableMap &RHS) const {
137    return Root && RHS.Root ? Root->isEqual(*RHS.Root) : Root == RHS.Root;
138  }
139
140  bool operator!=(const ImmutableMap &RHS) const {
141    return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root;
142  }
143
144  TreeTy *getRoot() const {
145    if (Root) { Root->retain(); }
146    return Root;
147  }
148
149  TreeTy *getRootWithoutRetain() const { return Root; }
150
151  void manualRetain() {
152    if (Root) Root->retain();
153  }
154
155  void manualRelease() {
156    if (Root) Root->release();
157  }
158
159  bool isEmpty() const { return !Root; }
160
161  //===--------------------------------------------------===//
162  // Foreach - A limited form of map iteration.
163  //===--------------------------------------------------===//
164
165private:
166  template <typename Callback>
167  struct CBWrapper {
168    Callback C;
169
170    void operator()(value_type_ref V) { C(V.first,V.second); }
171  };
172
173  template <typename Callback>
174  struct CBWrapperRef {
175    Callback &C;
176
177    CBWrapperRef(Callback& c) : C(c) {}
178
179    void operator()(value_type_ref V) { C(V.first,V.second); }
180  };
181
182public:
183  template <typename Callback>
184  void foreach(Callback& C) {
185    if (Root) {
186      CBWrapperRef<Callback> CB(C);
187      Root->foreach(CB);
188    }
189  }
190
191  template <typename Callback>
192  void foreach() {
193    if (Root) {
194      CBWrapper<Callback> CB;
195      Root->foreach(CB);
196    }
197  }
198
199  //===--------------------------------------------------===//
200  // For testing.
201  //===--------------------------------------------------===//
202
203  void verify() const { if (Root) Root->verify(); }
204
205  //===--------------------------------------------------===//
206  // Iterators.
207  //===--------------------------------------------------===//
208
209  class iterator : public ImutAVLValueIterator<ImmutableMap> {
210    friend class ImmutableMap;
211
212    iterator() = default;
213    explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
214
215  public:
216    key_type_ref getKey() const { return (*this)->first; }
217    data_type_ref getData() const { return (*this)->second; }
218  };
219
220  iterator begin() const { return iterator(Root); }
221  iterator end() const { return iterator(); }
222
223  data_type* lookup(key_type_ref K) const {
224    if (Root) {
225      TreeTy* T = Root->find(K);
226      if (T) return &T->getValue().second;
227    }
228
229    return nullptr;
230  }
231
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;
237  }
238
239  //===--------------------------------------------------===//
240  // Utility methods.
241  //===--------------------------------------------------===//
242
243  unsigned getHeight() const { return Root ? Root->getHeight() : 0; }
244
245  static inline void Profile(FoldingSetNodeID& ID, const ImmutableMap& M) {
246    ID.AddPointer(M.Root);
247  }
248
249  inline void Profile(FoldingSetNodeID& ID) const {
250    return Profile(ID,*this);
251  }
252};
253
254// NOTE: This will possibly become the new implementation of ImmutableMap some day.
255template <typename KeyT, typename ValT,
256typename ValInfo = ImutKeyValueInfo<KeyT,ValT>>
257class ImmutableMapRef {
258public:
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;
267
268protected:
269  TreeTy *Root;
270  FactoryTy *Factory;
271
272public:
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) {
279    if (Root) {
280      Root->retain();
281    }
282  }
283
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(); }
289  }
290
291  ImmutableMapRef(const ImmutableMapRef &X) : Root(X.Root), Factory(X.Factory) {
292    if (Root) {
293      Root->retain();
294    }
295  }
296
297  ~ImmutableMapRef() {
298    if (Root)
299      Root->release();
300  }
301
302  ImmutableMapRef &operator=(const ImmutableMapRef &X) {
303    if (Root != X.Root) {
304      if (X.Root)
305        X.Root->retain();
306
307      if (Root)
308        Root->release();
309
310      Root = X.Root;
311      Factory = X.Factory;
312    }
313    return *this;
314  }
315
316  static inline ImmutableMapRef getEmptyMap(FactoryTy *F) {
317    return ImmutableMapRef(0, F);
318  }
319
320  void manualRetain() {
321    if (Root) Root->retain();
322  }
323
324  void manualRelease() {
325    if (Root) Root->release();
326  }
327
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);
331  }
332
333  ImmutableMapRef remove(key_type_ref K) const {
334    TreeTy *NewT = Factory->remove(Root, K);
335    return ImmutableMapRef(NewT, Factory);
336  }
337
338  bool contains(key_type_ref K) const {
339    return Root ? Root->contains(K) : false;
340  }
341
342  ImmutableMap<KeyT, ValT> asImmutableMap() const {
343    return ImmutableMap<KeyT, ValT>(Factory->getCanonicalTree(Root));
344  }
345
346  bool operator==(const ImmutableMapRef &RHS) const {
347    return Root && RHS.Root ? Root->isEqual(*RHS.Root) : Root == RHS.Root;
348  }
349
350  bool operator!=(const ImmutableMapRef &RHS) const {
351    return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root;
352  }
353
354  bool isEmpty() const { return !Root; }
355
356  //===--------------------------------------------------===//
357  // For testing.
358  //===--------------------------------------------------===//
359
360  void verify() const {
361    if (Root)
362      Root->verify();
363  }
364
365  //===--------------------------------------------------===//
366  // Iterators.
367  //===--------------------------------------------------===//
368
369  class iterator : public ImutAVLValueIterator<ImmutableMapRef> {
370    friend class ImmutableMapRef;
371
372    iterator() = default;
373    explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
374
375  public:
376    key_type_ref getKey() const { return (*this)->first; }
377    data_type_ref getData() const { return (*this)->second; }
378  };
379
380  iterator begin() const { return iterator(Root); }
381  iterator end() const { return iterator(); }
382
383  data_type *lookup(key_type_ref K) const {
384    if (Root) {
385      TreeTy* T = Root->find(K);
386      if (T) return &T->getValue().second;
387    }
388
389    return nullptr;
390  }
391
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;
397  }
398
399  //===--------------------------------------------------===//
400  // Utility methods.
401  //===--------------------------------------------------===//
402
403  unsigned getHeight() const { return Root ? Root->getHeight() : 0; }
404
405  static inline void Profile(FoldingSetNodeID &ID, const ImmutableMapRef &M) {
406    ID.AddPointer(M.Root);
407  }
408
409  inline void Profile(FoldingSetNodeID &ID) const { return Profile(ID, *this); }
410};
411
412} // end namespace llvm
413
414#endif // LLVM_ADT_IMMUTABLEMAP_H
415