#include "llvm/Support/Allocator.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/DataTypes.h"
#include <cassert>
+#include <functional>
namespace llvm {
//===----------------------------------------------------------------------===//
template <typename ImutInfo> class ImutAVLFactory;
-
template <typename ImutInfo> class ImutAVLTreeInOrderIterator;
+template <typename ImutInfo> class ImutAVLTreeGenericIterator;
template <typename ImutInfo >
class ImutAVLTree : public FoldingSetNode {
typedef ImutAVLFactory<ImutInfo> Factory;
friend class ImutAVLFactory<ImutInfo>;
+ friend class ImutAVLTreeGenericIterator<ImutInfo>;
+ friend class FoldingSet<ImutAVLTree>;
+
typedef ImutAVLTreeInOrderIterator<ImutInfo> iterator;
//===----------------------------------------------------===//
/// 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
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;
&& "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.
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;
-
- ID.AddInteger(L ? L->ComputeHash() : 0);
- ImutInfo::Profile(ID,V);
- ID.AddInteger(R ? R->ComputeHash() : 0);
-
- return ID.ComputeHash();
- }
-
- 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
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;
+ }
};
//===----------------------------------------------------------------------===//
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);
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.
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
//===--------------------------------------------------===//
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) {
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()));
}
};
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;
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;
public:
Factory() {}
+ Factory(BumpPtrAllocator& Alloc)
+ : F(Alloc) {}
+
/// GetEmptySet - Returns an immutable set that contains no elements.
ImmutableSet GetEmptySet() { return ImmutableSet(F.GetEmptyTree()); }
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; }
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