//===--- ImmutableIntervalMap.h - Immutable (functional) map ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the ImmutableIntervalMap class. // //===----------------------------------------------------------------------===// #include "llvm/ADT/ImmutableMap.h" namespace llvm { class Interval { private: uint64_t Start; uint64_t End; public: Interval(uint64_t S, uint64_t E) : Start(S), End(E) {} uint64_t getStart() const { return Start; } uint64_t getEnd() const { return End; } }; template struct ImutIntervalInfo { typedef const std::pair value_type; typedef const value_type &value_type_ref; typedef const Interval key_type; typedef const Interval &key_type_ref; typedef const T data_type; typedef const T &data_type_ref; static key_type_ref KeyOfValue(value_type_ref V) { return V.first; } static data_type_ref DataOfValue(value_type_ref V) { return V.second; } static bool isEqual(key_type_ref L, key_type_ref R) { return L.getStart() == R.getStart() && L.getEnd() == R.getEnd(); } static bool isDataEqual(data_type_ref L, data_type_ref R) { return ImutContainerInfo::isEqual(L,R); } static bool isLess(key_type_ref L, key_type_ref R) { // Assume L and R does not overlap. if (L.getStart() < R.getStart()) { assert(L.getEnd() < R.getStart()); return true; } else if (L.getStart() == R.getStart()) { assert(L.getEnd() == R.getEnd()); return false; } else { assert(L.getStart() > R.getEnd()); return false; } } static void Profile(FoldingSetNodeID &ID, value_type_ref V) { ID.AddInteger(V.first.getStart()); ID.AddInteger(V.first.getEnd()); ImutProfileInfo::Profile(ID, V.second); } }; template class ImutIntervalAVLFactory; template class ImutIntervalAVLFactory : public ImutAVLFactory { typedef ImutAVLTree TreeTy; typedef typename ImutInfo::value_type value_type; typedef typename ImutInfo::value_type_ref value_type_ref; typedef typename ImutInfo::key_type key_type; typedef typename ImutInfo::key_type_ref key_type_ref; typedef typename ImutInfo::data_type data_type; typedef typename ImutInfo::data_type_ref data_type_ref; public: TreeTy *Add(TreeTy* T, value_type_ref V) { T = Add_internal(V,T); MarkImmutable(T); return T; } private: TreeTy *Add_internal(value_type_ref V, TreeTy *T) { if (isEmpty(T)) return CreateNode(NULL, V, NULL); assert(!T->isMutable()); key_type_ref K = ImutInfo::KeyOfValue(V); key_type_ref KCurrent = ImutInfo::KeyOfValue(Value(T)); T = RemoveAllOverlaps(T, K); if (ImutInfo::isLess(K, KCurrent)) return Balance(Add_internal(V, Left(T)), Value(T), Right(T)); else return Balance(Left(T), Value(T), Add_internal(V, Right(T))); } // Remove all overlaps from T. TreeTy *RemoveAllOverlaps(TreeTy *T, key_type_ref K) { TreeTy *OldTree, *NewTree; NewTree = T; do { OldTree = NewTree; NewTree = RemoveOverlap(OldTree, K); } while (NewTree != OldTree); } // Remove one overlap from T. TreeTy *RemoveOverlap(TreeTy *T, key_type_ref K) { Interval CurrentK = ImutInfo::KeyOfValue(Value(T)); // If current key does not overlap the inserted key. if (CurrentK.getStart() > K.getEnd()) return RemoveOverlap(Left(T), K); else if (CurrentK.getEnd() < K.getStart()) return RemoveOverlap(Right(T), K); // Current key overlaps with the inserted key. // Remove the current key. T = Remove_internal(CurrentK, T); // Add back the unoverlapped part of the current key. if (CurrentK.getStart() < K.getStart()) { if (CurrentK.getEnd() <= K.getEnd()) { Interval NewK(CurrentK.getStart(), K.getStart()-1); return Add_internal(std::make_pair(NewK, ImutInfo::DataOfValue(Value(T))), T); } else { Interval NewK1(CurrentK.getStart(), K.getStart()-1); T = Add_internal(std::make_pair(NewK1, ImutInfo::DataOfValue(Value(T))), T); Interval NewK2(K.getEnd()+1, CurrentK.getEnd()); return Add_internal(std::make_pair(NewK2, ImutInfo::DataOfValue(Value(T))), T); } } else { if (CurrentK.getEnd() > K.getEnd()) { Interval NewK(K.getEnd()+1, CurrentK.getEnd()); return Add_internal(std::make_pair(NewK, ImutInfo::DataOfValue(Value(T))), T); } } } }; /// ImmutableIntervalMap maps an interval [start, end] to a value. The intervals /// in the map are guaranteed to be disjoint. template class ImmutableIntervalMap : public ImmutableMap > { typedef typename ImutIntervalInfo::value_type value_type; typedef typename ImutIntervalInfo::value_type_ref value_type_ref; typedef typename ImutIntervalInfo::key_type key_type; typedef typename ImutIntervalInfo::key_type_ref key_type_ref; typedef typename ImutIntervalInfo::data_type data_type; typedef typename ImutIntervalInfo::data_type_ref data_type_ref; typedef ImutAVLTree > TreeTy; public: explicit ImmutableIntervalMap(TreeTy *R) : ImmutableMap >(R) {} class Factory { ImutIntervalAVLFactory > F; public: ImmutableIntervalMap GetEmptyMap() { return ImmutableIntervalMap(F.GetEmptyTree()); } ImmutableIntervalMap Add(ImmutableIntervalMap Old, key_type_ref K, data_type_ref D) { TreeTy *T = F.Add(Old.Root, std::make_pair(K, D)); return ImmutableIntervalMap(F.GetCanonicalTree(T)); } ImmutableIntervalMap Remove(ImmutableIntervalMap Old, key_type_ref K) { TreeTy *T = F.Remove(Old.Root, K); return ImmutableIntervalMap(F.GetCanonicalTree(T)); } }; }; } // end namespace llvm