• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- ImmutableIntervalMap.h - Immutable (functional) map  ---*- 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 ImmutableIntervalMap class.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_ADT_IMMUTABLE_INTERVAL_MAP_H
15 #define LLVM_ADT_IMMUTABLE_INTERVAL_MAP_H
16 
17 #include "llvm/ADT/ImmutableMap.h"
18 
19 namespace llvm {
20 
21 class Interval {
22 private:
23   int64_t Start;
24   int64_t End;
25 
26 public:
Interval(int64_t S,int64_t E)27   Interval(int64_t S, int64_t E) : Start(S), End(E) {}
28 
getStart()29   int64_t getStart() const { return Start; }
getEnd()30   int64_t getEnd() const { return End; }
31 };
32 
33 template <typename T>
34 struct ImutIntervalInfo {
35   typedef const std::pair<Interval, T> value_type;
36   typedef const value_type &value_type_ref;
37   typedef const Interval key_type;
38   typedef const Interval &key_type_ref;
39   typedef const T data_type;
40   typedef const T &data_type_ref;
41 
KeyOfValueImutIntervalInfo42   static key_type_ref KeyOfValue(value_type_ref V) {
43     return V.first;
44   }
45 
DataOfValueImutIntervalInfo46   static data_type_ref DataOfValue(value_type_ref V) {
47     return V.second;
48   }
49 
isEqualImutIntervalInfo50   static bool isEqual(key_type_ref L, key_type_ref R) {
51     return L.getStart() == R.getStart() && L.getEnd() == R.getEnd();
52   }
53 
isDataEqualImutIntervalInfo54   static bool isDataEqual(data_type_ref L, data_type_ref R) {
55     return ImutContainerInfo<T>::isEqual(L,R);
56   }
57 
isLessImutIntervalInfo58   static bool isLess(key_type_ref L, key_type_ref R) {
59     // Assume L and R does not overlap.
60     if (L.getStart() < R.getStart()) {
61       assert(L.getEnd() < R.getStart());
62       return true;
63     } else if (L.getStart() == R.getStart()) {
64       assert(L.getEnd() == R.getEnd());
65       return false;
66     } else {
67       assert(L.getStart() > R.getEnd());
68       return false;
69     }
70   }
71 
isContainedInImutIntervalInfo72   static bool isContainedIn(key_type_ref K, key_type_ref L) {
73     if (K.getStart() >= L.getStart() && K.getEnd() <= L.getEnd())
74       return true;
75     else
76       return false;
77   }
78 
ProfileImutIntervalInfo79   static void Profile(FoldingSetNodeID &ID, value_type_ref V) {
80     ID.AddInteger(V.first.getStart());
81     ID.AddInteger(V.first.getEnd());
82     ImutProfileInfo<T>::Profile(ID, V.second);
83   }
84 };
85 
86 template <typename ImutInfo>
87 class ImutIntervalAVLFactory : public ImutAVLFactory<ImutInfo> {
88   typedef ImutAVLTree<ImutInfo> TreeTy;
89   typedef typename ImutInfo::value_type     value_type;
90   typedef typename ImutInfo::value_type_ref value_type_ref;
91   typedef typename ImutInfo::key_type       key_type;
92   typedef typename ImutInfo::key_type_ref   key_type_ref;
93   typedef typename ImutInfo::data_type      data_type;
94   typedef typename ImutInfo::data_type_ref  data_type_ref;
95 
96 public:
ImutIntervalAVLFactory(BumpPtrAllocator & Alloc)97   ImutIntervalAVLFactory(BumpPtrAllocator &Alloc)
98     : ImutAVLFactory<ImutInfo>(Alloc) {}
99 
Add(TreeTy * T,value_type_ref V)100   TreeTy *Add(TreeTy *T, value_type_ref V) {
101     T = add_internal(V,T);
102     this->MarkImmutable(T);
103     return T;
104   }
105 
Find(TreeTy * T,key_type_ref K)106   TreeTy *Find(TreeTy *T, key_type_ref K) {
107     if (!T)
108       return NULL;
109 
110     key_type_ref CurrentKey = ImutInfo::KeyOfValue(this->getValue(T));
111 
112     if (ImutInfo::isContainedIn(K, CurrentKey))
113       return T;
114     else if (ImutInfo::isLess(K, CurrentKey))
115       return Find(this->getLeft(T), K);
116     else
117       return Find(this->getRight(T), K);
118   }
119 
120 private:
add_internal(value_type_ref V,TreeTy * T)121   TreeTy *add_internal(value_type_ref V, TreeTy *T) {
122     key_type_ref K = ImutInfo::KeyOfValue(V);
123     T = removeAllOverlaps(T, K);
124     if (this->isEmpty(T))
125       return this->CreateNode(NULL, V, NULL);
126 
127     assert(!T->isMutable());
128 
129     key_type_ref KCurrent = ImutInfo::KeyOfValue(this->Value(T));
130 
131     if (ImutInfo::isLess(K, KCurrent))
132       return this->Balance(add_internal(V, this->Left(T)), this->Value(T),
133                                         this->Right(T));
134     else
135       return this->Balance(this->Left(T), this->Value(T),
136                            add_internal(V, this->Right(T)));
137   }
138 
139   // Remove all overlaps from T.
removeAllOverlaps(TreeTy * T,key_type_ref K)140   TreeTy *removeAllOverlaps(TreeTy *T, key_type_ref K) {
141     bool Changed;
142     do {
143       Changed = false;
144       T = removeOverlap(T, K, Changed);
145       this->markImmutable(T);
146     } while (Changed);
147 
148     return T;
149   }
150 
151   // Remove one overlap from T.
removeOverlap(TreeTy * T,key_type_ref K,bool & Changed)152   TreeTy *removeOverlap(TreeTy *T, key_type_ref K, bool &Changed) {
153     if (!T)
154       return NULL;
155     Interval CurrentK = ImutInfo::KeyOfValue(this->Value(T));
156 
157     // If current key does not overlap the inserted key.
158     if (CurrentK.getStart() > K.getEnd())
159       return this->Balance(removeOverlap(this->Left(T), K, Changed),
160                            this->Value(T), this->Right(T));
161     else if (CurrentK.getEnd() < K.getStart())
162       return this->Balance(this->Left(T), this->Value(T),
163                            removeOverlap(this->Right(T), K, Changed));
164 
165     // Current key overlaps with the inserted key.
166     // Remove the current key.
167     Changed = true;
168     data_type_ref OldData = ImutInfo::DataOfValue(this->Value(T));
169     T = this->Remove_internal(CurrentK, T);
170     // Add back the unoverlapped part of the current key.
171     if (CurrentK.getStart() < K.getStart()) {
172       if (CurrentK.getEnd() <= K.getEnd()) {
173         Interval NewK(CurrentK.getStart(), K.getStart()-1);
174         return add_internal(std::make_pair(NewK, OldData), T);
175       } else {
176         Interval NewK1(CurrentK.getStart(), K.getStart()-1);
177         T = add_internal(std::make_pair(NewK1, OldData), T);
178 
179         Interval NewK2(K.getEnd()+1, CurrentK.getEnd());
180         return add_internal(std::make_pair(NewK2, OldData), T);
181       }
182     } else {
183       if (CurrentK.getEnd() > K.getEnd()) {
184         Interval NewK(K.getEnd()+1, CurrentK.getEnd());
185         return add_internal(std::make_pair(NewK, OldData), T);
186       } else
187         return T;
188     }
189   }
190 };
191 
192 /// ImmutableIntervalMap maps an interval [start, end] to a value. The intervals
193 /// in the map are guaranteed to be disjoint.
194 template <typename ValT>
195 class ImmutableIntervalMap
196   : public ImmutableMap<Interval, ValT, ImutIntervalInfo<ValT> > {
197 
198   typedef typename ImutIntervalInfo<ValT>::value_type      value_type;
199   typedef typename ImutIntervalInfo<ValT>::value_type_ref  value_type_ref;
200   typedef typename ImutIntervalInfo<ValT>::key_type        key_type;
201   typedef typename ImutIntervalInfo<ValT>::key_type_ref    key_type_ref;
202   typedef typename ImutIntervalInfo<ValT>::data_type       data_type;
203   typedef typename ImutIntervalInfo<ValT>::data_type_ref   data_type_ref;
204   typedef ImutAVLTree<ImutIntervalInfo<ValT> > TreeTy;
205 
206 public:
ImmutableIntervalMap(TreeTy * R)207   explicit ImmutableIntervalMap(TreeTy *R)
208     : ImmutableMap<Interval, ValT, ImutIntervalInfo<ValT> >(R) {}
209 
210   class Factory {
211     ImutIntervalAVLFactory<ImutIntervalInfo<ValT> > F;
212 
213   public:
Factory(BumpPtrAllocator & Alloc)214     Factory(BumpPtrAllocator& Alloc) : F(Alloc) {}
215 
getEmptyMap()216     ImmutableIntervalMap getEmptyMap() {
217       return ImmutableIntervalMap(F.getEmptyTree());
218     }
219 
add(ImmutableIntervalMap Old,key_type_ref K,data_type_ref D)220     ImmutableIntervalMap add(ImmutableIntervalMap Old,
221                              key_type_ref K, data_type_ref D) {
222       TreeTy *T = F.add(Old.Root, std::pair<key_type, data_type>(K, D));
223       return ImmutableIntervalMap(F.getCanonicalTree(T));
224     }
225 
remove(ImmutableIntervalMap Old,key_type_ref K)226     ImmutableIntervalMap remove(ImmutableIntervalMap Old, key_type_ref K) {
227       TreeTy *T = F.remove(Old.Root, K);
228       return ImmutableIntervalMap(F.getCanonicalTree(T));
229     }
230 
lookup(ImmutableIntervalMap M,key_type_ref K)231     data_type *lookup(ImmutableIntervalMap M, key_type_ref K) {
232       TreeTy *T = F.Find(M.getRoot(), K);
233       if (T)
234         return &T->getValue().second;
235       else
236         return 0;
237     }
238   };
239 
240 private:
241   // For ImmutableIntervalMap, the lookup operation has to be done by the
242   // factory.
243   data_type* lookup(key_type_ref K) const;
244 };
245 
246 } // end namespace llvm
247 
248 #endif
249