diff --git a/include/llvm/ADT/ImmutableIntervalMap.h b/include/llvm/ADT/ImmutableIntervalMap.h new file mode 100644 index 00000000000..cc4dd777938 --- /dev/null +++ b/include/llvm/ADT/ImmutableIntervalMap.h @@ -0,0 +1,199 @@ +//===--- 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 diff --git a/include/llvm/ADT/ImmutableMap.h b/include/llvm/ADT/ImmutableMap.h index 1b3f1a911eb..7c0a8c964e5 100644 --- a/include/llvm/ADT/ImmutableMap.h +++ b/include/llvm/ADT/ImmutableMap.h @@ -68,7 +68,7 @@ public: typedef typename ValInfo::data_type_ref data_type_ref; typedef ImutAVLTree TreeTy; -private: +protected: TreeTy* Root; public: diff --git a/include/llvm/ADT/ImmutableSet.h b/include/llvm/ADT/ImmutableSet.h index dcead4c5c79..65e70e279ab 100644 --- a/include/llvm/ADT/ImmutableSet.h +++ b/include/llvm/ADT/ImmutableSet.h @@ -27,6 +27,7 @@ namespace llvm { //===----------------------------------------------------------------------===// template class ImutAVLFactory; +template class ImutIntervalAVLFactory; template class ImutAVLTreeInOrderIterator; template class ImutAVLTreeGenericIterator; @@ -39,6 +40,7 @@ public: typedef ImutAVLFactory Factory; friend class ImutAVLFactory; + friend class ImutIntervalAVLFactory; friend class ImutAVLTreeGenericIterator; friend class FoldingSet; @@ -389,7 +391,7 @@ public: // These have succinct names so that the balancing code // is as terse (and readable) as possible. //===--------------------------------------------------===// -private: +protected: bool isEmpty(TreeTy* T) const { return !T; } unsigned Height(TreeTy* T) const { return T ? T->getHeight() : 0; }