Add missing include (for ptrdiff_t).
[oota-llvm.git] / include / llvm / ADT / ImmutableSet.h
index 11724603647e855ae4ff129043261e56a49cd0fe..c351771c6da22413c9f4b88f0199ae6d2d6d8d6a 100644 (file)
@@ -16,7 +16,9 @@
 
 #include "llvm/Support/Allocator.h"
 #include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/DataTypes.h"
 #include <cassert>
+#include <functional>
 
 namespace llvm {
   
@@ -25,8 +27,8 @@ namespace llvm {
 //===----------------------------------------------------------------------===//
 
 template <typename ImutInfo> class ImutAVLFactory;
-
 template <typename ImutInfo> class ImutAVLTreeInOrderIterator;
+template <typename ImutInfo> class ImutAVLTreeGenericIterator;
   
 template <typename ImutInfo >
 class ImutAVLTree : public FoldingSetNode {
@@ -38,6 +40,9 @@ public:
   typedef ImutAVLFactory<ImutInfo>          Factory;
   friend class ImutAVLFactory<ImutInfo>;
   
+  friend class ImutAVLTreeGenericIterator<ImutInfo>;
+  friend class FoldingSet<ImutAVLTree>;
+  
   typedef ImutAVLTreeInOrderIterator<ImutInfo>  iterator;
   
   //===----------------------------------------------------===//  
@@ -102,6 +107,24 @@ public:
   /// end - Returns an iterator for the tree that denotes the end of an
   ///  inorder traversal.
   iterator end() const { return iterator(); }
+    
+  bool ElementEqual(value_type_ref V) const {
+    // Compare the keys.
+    if (!ImutInfo::isEqual(ImutInfo::KeyOfValue(getValue()),
+                           ImutInfo::KeyOfValue(V)))
+      return false;
+    
+    // Also compare the data values.
+    if (!ImutInfo::isDataEqual(ImutInfo::DataOfValue(getValue()),
+                               ImutInfo::DataOfValue(V)))
+      return false;
+    
+    return true;
+  }
+  
+  bool ElementEqual(const ImutAVLTree* RHS) const {
+    return ElementEqual(RHS->getValue());
+  }
   
   /// isEqual - Compares two trees for structural equality and returns true
   ///   if they are equal.  This worst case performance of this operation is
@@ -120,14 +143,7 @@ public:
         continue;
       }
       
-      // Compare the keys.
-      if (!ImutInfo::isEqual(ImutInfo::KeyOfValue(LItr->getValue()),
-                             ImutInfo::KeyOfValue(RItr->getValue())))
-        return false;
-      
-      // Also compare the data values.
-      if (!ImutInfo::isDataEqual(ImutInfo::DataOfValue(LItr->getValue()),
-                                 ImutInfo::DataOfValue(RItr->getValue())))
+      if (!LItr->ElementEqual(*RItr))
         return false;
       
       ++LItr;
@@ -187,7 +203,12 @@ public:
             && "Current value is not less that value of right child.");
     
     return getHeight();
-  }  
+  }
+  
+  /// Profile - Profiling for ImutAVLTree.
+  void Profile(llvm::FoldingSetNodeID& ID) {
+    ID.AddInteger(ComputeDigest());
+  }
   
   //===----------------------------------------------------===//  
   // Internal Values.
@@ -198,74 +219,21 @@ private:
   ImutAVLTree*     Right;
   unsigned         Height;
   value_type       Value;
-  unsigned         Hash;
-  
-  //===----------------------------------------------------===//  
-  // Profiling or FoldingSet.
-  //===----------------------------------------------------===//
-
-private:
-
-  static inline
-  unsigned ComputeHash(ImutAVLTree* L, ImutAVLTree* R, value_type_ref V) {
-    FoldingSetNodeID ID;
-    
-    if (L) ID.AddInteger(L->ComputeHash());
-    ImutInfo::Profile(ID,V);
-    
-    // Compute the "intermediate" hash.  Basically, we want the net profile to
-    // be:  H(H(....H(H(H(item0),item1),item2)...),itemN), where
-    //  H(item) is the hash of the data item and H(hash,item) is a hash
-    //  of the last item hash and the the next item.
-    
-    unsigned X = ID.ComputeHash();
-    
-    if (R) {
-      ID.clear();
-      ID.AddInteger(X);
-      ID.AddInteger(R->ComputeHash());
-      X = ID.ComputeHash();
-    }
-    
-    return X;
-  }
-  
-  inline unsigned ComputeHash() {
-    if (!isMutable() && Hash) return Hash;
-    Hash = ComputeHash(getSafeLeft(), getRight(), getValue());
-    return Hash;
-  }    
-  
-  /// Profile - Generates a FoldingSet profile for a tree node before it is
-  ///   created.  This is used by the ImutAVLFactory when creating
-  ///   trees.
-  static inline
-  void Profile(FoldingSetNodeID& ID, ImutAVLTree* L, ImutAVLTree* R,
-               value_type_ref V) {
-    
-    ID.AddInteger(ComputeHash(L, R, V));
-  }
-  
-public:
-
-  /// Profile - Generates a FoldingSet profile for an existing tree node.
-  void Profile(FoldingSetNodeID& ID) {
-    ID.AddInteger(ComputeHash());
-  }
+  unsigned         Digest;
   
   //===----------------------------------------------------===//    
   // Internal methods (node manipulation; used by Factory).
   //===----------------------------------------------------===//
-  
+
 private:
   
   enum { Mutable = 0x1 };
-  
+
   /// ImutAVLTree - Internal constructor that is only called by
   ///   ImutAVLFactory.
   ImutAVLTree(ImutAVLTree* l, ImutAVLTree* r, value_type_ref v, unsigned height)
   : Left(reinterpret_cast<uintptr_t>(l) | Mutable),
-    Right(r), Height(height), Value(v), Hash(0) {}
+    Right(r), Height(height), Value(v), Digest(0) {}
   
   
   /// isMutable - Returns true if the left and right subtree references
@@ -327,6 +295,33 @@ private:
     assert (isMutable() && "Only a mutable tree can have its height changed.");
     Height = h;
   }
+  
+  
+  static inline
+  unsigned ComputeDigest(ImutAVLTree* L, ImutAVLTree* R, value_type_ref V) {
+    unsigned digest = 0;
+    
+    if (L) digest += L->ComputeDigest();
+    
+    { // Compute digest of stored data.
+      FoldingSetNodeID ID;
+      ImutInfo::Profile(ID,V);
+      digest += ID.ComputeHash();
+    }
+    
+    if (R) digest += R->ComputeDigest();
+    
+    return digest;
+  }
+  
+  inline unsigned ComputeDigest() {
+    if (Digest) return Digest;
+    
+    unsigned X = ComputeDigest(getSafeLeft(), getRight(), getValue());
+    if (!isMutable()) Digest = X;
+    
+    return X;
+  }
 };
 
 //===----------------------------------------------------------------------===//    
@@ -341,15 +336,31 @@ class ImutAVLFactory {
   
   typedef FoldingSet<TreeTy> CacheTy;
   
-  CacheTy Cache;  
-  BumpPtrAllocator Allocator;    
+  CacheTy Cache;
+  uintptr_t Allocator;
+  
+  bool ownsAllocator() const {
+    return Allocator & 0x1 ? false : true;
+  }
+
+  BumpPtrAllocator& getAllocator() const { 
+    return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1);
+  }
   
   //===--------------------------------------------------===//    
   // Public interface.
   //===--------------------------------------------------===//
   
 public:
-  ImutAVLFactory() {}
+  ImutAVLFactory()
+    : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {}
+  
+  ImutAVLFactory(BumpPtrAllocator& Alloc)
+    : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {}
+  
+  ~ImutAVLFactory() {
+    if (ownsAllocator()) delete &getAllocator();
+  }
   
   TreeTy* Add(TreeTy* T, value_type_ref V) {
     T = Add_internal(V,T);
@@ -365,8 +376,6 @@ public:
   
   TreeTy* GetEmptyTree() const { return NULL; }
   
-  BumpPtrAllocator& getAllocator() { return Allocator; }
-  
   //===--------------------------------------------------===//    
   // A bunch of quick helper functions used for reasoning
   // about the properties of trees and their children.
@@ -387,6 +396,20 @@ private:
     return ( hl > hr ? hl : hr ) + 1;
   }
   
+  
+  static bool CompareTreeWithSection(TreeTy* T,
+                                     typename TreeTy::iterator& TI,
+                                     typename TreeTy::iterator& TE) {
+    
+    typename TreeTy::iterator I = T->begin(), E = T->end();
+    
+    for ( ; I!=E ; ++I, ++TI)
+      if (TI == TE || !I->ElementEqual(*TI))
+        return false;
+
+    return true;
+  }                     
+  
   //===--------------------------------------------------===//    
   // "CreateNode" is used to generate new tree roots that link
   // to other trees.  The functon may also simply move links
@@ -398,21 +421,62 @@ private:
   //===--------------------------------------------------===//
   
   TreeTy* CreateNode(TreeTy* L, value_type_ref V, TreeTy* R) {
-    FoldingSetNodeID ID;      
-    TreeTy::Profile(ID,L,R,V);      
-    void* InsertPos;
+    // Search the FoldingSet bucket for a Tree with the same digest.
+    FoldingSetNodeID ID;
+    unsigned digest = TreeTy::ComputeDigest(L, R, V);
+    ID.AddInteger(digest);
+    unsigned hash = ID.ComputeHash();
     
-    if (TreeTy* T = Cache.FindNodeOrInsertPos(ID,InsertPos))
-      return T;
+    typename CacheTy::bucket_iterator I = Cache.bucket_begin(hash);
+    typename CacheTy::bucket_iterator E = Cache.bucket_end(hash);
     
-    assert (InsertPos != NULL);
+    for (; I != E; ++I) {
+      TreeTy* T = &*I;
+
+      if (T->ComputeDigest() != digest)
+        continue;
+      
+      // We found a collision.  Perform a comparison of Contents('T')
+      // with Contents('L')+'V'+Contents('R').
+      
+      typename TreeTy::iterator TI = T->begin(), TE = T->end();
+      
+      // First compare Contents('L') with the (initial) contents of T.
+      if (!CompareTreeWithSection(L, TI, TE))
+        continue;
+      
+      // Now compare the new data element.
+      if (TI == TE || !TI->ElementEqual(V))
+        continue;
+      
+      ++TI;
+
+      // Now compare the remainder of 'T' with 'R'.
+      if (!CompareTreeWithSection(R, TI, TE))
+        continue;
+      
+      if (TI != TE) // Contents('R') did not match suffix of 'T'.
+        continue;
+      
+      // Trees did match!  Return 'T'.
+      return T;
+    }
     
+    // No tree with the contents: Contents('L')+'V'+Contents('R').
+    // Create it.
+
     // Allocate the new tree node and insert it into the cache.
-    TreeTy* T = (TreeTy*) Allocator.Allocate<TreeTy>();    
+    BumpPtrAllocator& A = getAllocator();
+    TreeTy* T = (TreeTy*) A.Allocate<TreeTy>();
     new (T) TreeTy(L,R,V,IncrementHeight(L,R));
-    Cache.InsertNode(T,InsertPos);
 
-    return T;      
+    // We do not insert 'T' into the FoldingSet here.  This is because
+    // this tree is still mutable and things may get rebalanced.
+    // Because our digest is associative and based on the contents of
+    // the set, this should hopefully not cause any strange bugs.
+    // 'T' is inserted by 'MarkImmutable'.
+
+    return T;
   }
   
   TreeTy* CreateNode(TreeTy* L, TreeTy* OldTree, TreeTy* R) {      
@@ -543,6 +607,12 @@ private:
     T->MarkImmutable();
     MarkImmutable(Left(T));
     MarkImmutable(Right(T));
+        
+    // Now that the node is immutable it can safely be inserted
+    // into the node cache.
+    llvm::FoldingSetNodeID ID;
+    ID.AddInteger(T->ComputeDigest());
+    Cache.InsertNode(T, (void*) &*Cache.bucket_end(ID.ComputeHash()));
   }
 };
   
@@ -623,7 +693,7 @@ public:
     
     switch (getVisitState()) {
       case VisitedNone:
-        if (TreeTy* L = Current->getLeft())
+        if (TreeTy* L = Current->getSafeLeft())
           stack.push_back(reinterpret_cast<uintptr_t>(L));
         else
           stack.back() |= VisitedLeft;
@@ -859,14 +929,17 @@ class ImmutableSet {
 public:
   typedef typename ValInfo::value_type      value_type;
   typedef typename ValInfo::value_type_ref  value_type_ref;
-  
-private:  
   typedef ImutAVLTree<ValInfo> TreeTy;
+
+private:  
   TreeTy* Root;
-  
-  ImmutableSet(TreeTy* R) : Root(R) {}
-  
+
 public:
+  /// Constructs a set from a pointer to a tree root.  In general one
+  /// should use a Factory object to create sets instead of directly
+  /// invoking the constructor, but there are cases where make this
+  /// constructor public is useful.
+  explicit ImmutableSet(TreeTy* R) : Root(R) {}
   
   class Factory {
     typename TreeTy::Factory F;
@@ -874,6 +947,9 @@ public:
   public:
     Factory() {}
     
+    Factory(BumpPtrAllocator& Alloc)
+      : F(Alloc) {}
+    
     /// GetEmptySet - Returns an immutable set that contains no elements.
     ImmutableSet GetEmptySet() { return ImmutableSet(F.GetEmptyTree()); }
     
@@ -921,6 +997,8 @@ public:
     return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root;
   }
   
+  TreeTy* getRoot() const { return Root; }
+  
   /// isEmpty - Return true if the set contains no elements.
   bool isEmpty() const { return !Root; }
   
@@ -953,12 +1031,25 @@ public:
   iterator begin() const { return iterator(Root); }
   iterator end() const { return iterator(); }  
   
+  //===--------------------------------------------------===//    
+  // Utility methods.
+  //===--------------------------------------------------===//  
+  
+  inline unsigned getHeight() const { return Root ? Root->getHeight() : 0; }
+  
+  static inline void Profile(FoldingSetNodeID& ID, const ImmutableSet& S) {
+    ID.AddPointer(S.Root);
+  }
+  
+  inline void Profile(FoldingSetNodeID& ID) const {
+    return Profile(ID,*this);
+  }
+  
   //===--------------------------------------------------===//    
   // For testing.
   //===--------------------------------------------------===//  
   
   void verify() const { if (Root) Root->verify(); }
-  unsigned getHeight() const { return Root ? Root->getHeight() : 0; }
 };
 
 } // end namespace llvm