template <typename ImutInfo >
class ImutAVLTree : public FoldingSetNode {
- struct ComputeIsEqual;
public:
typedef typename ImutInfo::key_type_ref key_type_ref;
typedef typename ImutInfo::value_type value_type;
// Public Interface.
//===----------------------------------------------------===//
- ImutAVLTree* getLeft() const { return reinterpret_cast<ImutAVLTree*>(Left); }
+ /// getLeft - Returns a pointer to the left subtree. This value
+ /// is NULL if there is no left subtree.
+ ImutAVLTree* getLeft() const {
+ assert (!isMutable() && "Node is incorrectly marked mutable.");
+
+ return reinterpret_cast<ImutAVLTree*>(Left);
+ }
+ /// getRight - Returns a pointer to the right subtree. This value is
+ /// NULL if there is no right subtree.
ImutAVLTree* getRight() const { return Right; }
+
+ /// getHeight - Returns the height of the tree. A tree with no subtrees
+ /// has a height of 1.
unsigned getHeight() const { return Height; }
+ /// getValue - Returns the data value associated with the tree node.
const value_type& getValue() const { return Value; }
+ /// find - Finds the subtree associated with the specified key value.
+ /// This method returns NULL if no matching subtree is found.
ImutAVLTree* find(key_type_ref K) {
ImutAVLTree *T = this;
return NULL;
}
+ /// size - Returns the number of nodes in the tree, which includes
+ /// both leaves and non-leaf nodes.
unsigned size() const {
unsigned n = 1;
return n;
}
+ /// begin - Returns an iterator that iterates over the nodes of the tree
+ /// in an inorder traversal. The returned iterator thus refers to the
+ /// the tree node with the minimum data element.
iterator begin() const { return iterator(this); }
+
+ /// end - Returns an iterator for the tree that denotes the end of an
+ /// inorder traversal.
iterator end() const { return iterator(); }
+ /// isEqual - Compares two trees for structural equality and returns true
+ /// if they are equal. This worst case performance of this operation is
+ // linear in the sizes of the trees.
bool isEqual(const ImutAVLTree& RHS) const {
if (&RHS == this)
return true;
return LItr == LEnd && RItr == REnd;
}
-
+
+ /// isNotEqual - Compares two trees for structural inequality. Performance
+ /// is the same is isEqual.
bool isNotEqual(const ImutAVLTree& RHS) const { return !isEqual(RHS); }
+ /// contains - Returns true if this tree contains a subtree (node) that
+ /// has an data element that matches the specified key. Complexity
+ /// is logarithmic in the size of the tree.
bool contains(const key_type_ref K) { return (bool) find(K); }
+ /// foreach - A member template the accepts invokes operator() on a functor
+ /// object (specifed by Callback) for every node/subtree in the tree.
+ /// Nodes are visited using an inorder traversal.
template <typename Callback>
void foreach(Callback& C) {
if (ImutAVLTree* L = getLeft()) L->foreach(C);
if (ImutAVLTree* R = getRight()) R->foreach(C);
}
+ /// verify - A utility method that checks that the balancing and
+ /// ordering invariants of the tree are satisifed. It is a recursive
+ /// method that returns the height of the tree, which is then consumed
+ /// by the enclosing verify call. External callers should ignore the
+ /// return value. An invalid tree will cause an assertion to fire in
+ /// a debug build.
unsigned verify() const {
unsigned HL = getLeft() ? getLeft()->verify() : 0;
unsigned HR = getRight() ? getRight()->verify() : 0;
//===----------------------------------------------------===//
// Profiling or FoldingSet.
//===----------------------------------------------------===//
-
+
+private:
+
+ /// 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,
- unsigned H, value_type_ref V) {
+ value_type_ref V) {
ID.AddPointer(L);
ID.AddPointer(R);
- ID.AddInteger(H);
ImutInfo::Profile(ID,V);
}
public:
-
+
+ /// Profile - Generates a FoldingSet profile for an existing tree node.
void Profile(FoldingSetNodeID& ID) {
- Profile(ID,getSafeLeft(),getRight(),getHeight(),getValue());
+ Profile(ID,getSafeLeft(),getRight(),getValue());
}
//===----------------------------------------------------===//
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) | 0x1),
+ : Left(reinterpret_cast<uintptr_t>(l) | Mutable),
Right(r), Height(height), Value(v) {}
- bool isMutable() const { return Left & 0x1; }
+ /// isMutable - Returns true if the left and right subtree references
+ /// (as well as height) can be changed. If this method returns false,
+ /// the tree is truly immutable. Trees returned from an ImutAVLFactory
+ /// object should always have this method return true. Further, if this
+ /// method returns false for an instance of ImutAVLTree, all subtrees
+ /// will also have this method return false. The converse is not true.
+ bool isMutable() const { return Left & Mutable; }
+
+ /// getSafeLeft - Returns the pointer to the left tree by always masking
+ /// out the mutable bit. This is used internally by ImutAVLFactory,
+ /// as no trees returned to the client should have the mutable flag set.
ImutAVLTree* getSafeLeft() const {
- return reinterpret_cast<ImutAVLTree*>(Left & ~0x1);
+ return reinterpret_cast<ImutAVLTree*>(Left & ~Mutable);
}
- // Mutating operations. A tree root can be manipulated as long as
- // its reference has not "escaped" from internal methods of a
- // factory object (see below). When a tree pointer is externally
- // viewable by client code, the internal "mutable bit" is cleared
- // to mark the tree immutable. Note that a tree that still has
- // its mutable bit set may have children (subtrees) that are themselves
+ //===----------------------------------------------------===//
+ // Mutating operations. A tree root can be manipulated as
+ // long as its reference has not "escaped" from internal
+ // methods of a factory object (see below). When a tree
+ // pointer is externally viewable by client code, the
+ // internal "mutable bit" is cleared to mark the tree
+ // immutable. Note that a tree that still has its mutable
+ // bit set may have children (subtrees) that are themselves
// immutable.
+ //===----------------------------------------------------===//
+
- void RemoveMutableFlag() {
- assert (Left & 0x1 && "Mutable flag already removed.");
- Left &= ~0x1;
+ /// MarkImmutable - Clears the mutable flag for a tree. After this happens,
+ /// it is an error to call setLeft(), setRight(), and setHeight(). It
+ /// is also then safe to call getLeft() instead of getSafeLeft().
+ void MarkImmutable() {
+ assert (isMutable() && "Mutable flag already removed.");
+ Left &= ~Mutable;
}
+ /// setLeft - Changes the reference of the left subtree. Used internally
+ /// by ImutAVLFactory.
void setLeft(ImutAVLTree* NewLeft) {
- assert (isMutable());
- Left = reinterpret_cast<uintptr_t>(NewLeft) | 0x1;
+ assert (isMutable() &&
+ "Only a mutable tree can have its left subtree changed.");
+
+ Left = reinterpret_cast<uintptr_t>(NewLeft) | Mutable;
}
+ /// setRight - Changes the reference of the right subtree. Used internally
+ /// by ImutAVLFactory.
void setRight(ImutAVLTree* NewRight) {
- assert (isMutable());
+ assert (isMutable() &&
+ "Only a mutable tree can have its right subtree changed.");
+
Right = NewRight;
}
+ /// setHeight - Changes the height of the tree. Used internally by
+ /// ImutAVLFactory.
void setHeight(unsigned h) {
- assert (isMutable());
+ assert (isMutable() && "Only a mutable tree can have its height changed.");
Height = h;
}
};
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.
//===--------------------------------------------------===//
private:
- bool isEmpty(TreeTy* T) const {
- return !T;
- }
-
- unsigned Height(TreeTy* T) const {
- return T ? T->getHeight() : 0;
- }
-
- TreeTy* Left(TreeTy* T) const {
- assert (T);
- return T->getSafeLeft();
- }
-
- TreeTy* Right(TreeTy* T) const {
- assert (T);
- return T->getRight();
- }
-
- value_type_ref Value(TreeTy* T) const {
- assert (T);
- return T->Value;
- }
+ bool isEmpty(TreeTy* T) const { return !T; }
+ unsigned Height(TreeTy* T) const { return T ? T->getHeight() : 0; }
+ TreeTy* Left(TreeTy* T) const { return T->getSafeLeft(); }
+ TreeTy* Right(TreeTy* T) const { return T->getRight(); }
+ value_type_ref Value(TreeTy* T) const { return T->Value; }
unsigned IncrementHeight(TreeTy* L, TreeTy* R) const {
unsigned hl = Height(L);
TreeTy* CreateNode(TreeTy* L, value_type_ref V, TreeTy* R) {
FoldingSetNodeID ID;
- unsigned height = IncrementHeight(L,R);
-
- TreeTy::Profile(ID,L,R,height,V);
+ TreeTy::Profile(ID,L,R,V);
void* InsertPos;
if (TreeTy* T = Cache.FindNodeOrInsertPos(ID,InsertPos))
assert (InsertPos != NULL);
- // FIXME: more intelligent calculation of alignment.
- TreeTy* T = (TreeTy*) Allocator.Allocate(sizeof(*T),16);
- new (T) TreeTy(L,R,V,height);
-
+ // Allocate the new tree node and insert it into the cache.
+ TreeTy* T = (TreeTy*) Allocator.Allocate<TreeTy>();
+ new (T) TreeTy(L,R,V,IncrementHeight(L,R));
Cache.InsertNode(T,InsertPos);
+
return T;
}
if (!T || !T->isMutable())
return;
- T->RemoveMutableFlag();
+ T->MarkImmutable();
MarkImmutable(Left(T));
MarkImmutable(Right(T));
}
inline bool operator!=(const _Self& x) const { return !operator==(x); }
- inline TreeTy* operator*() { return *InternalItr; }
- inline TreeTy* operator->() { return *InternalItr; }
+ inline TreeTy* operator*() const { return *InternalItr; }
+ inline TreeTy* operator->() const { return *InternalItr; }
inline _Self& operator++() {
do ++InternalItr;
public:
Factory() {}
+ /// GetEmptySet - Returns an immutable set that contains no elements.
ImmutableSet GetEmptySet() { return ImmutableSet(F.GetEmptyTree()); }
+ /// Add - Creates a new immutable set that contains all of the values
+ /// of the original set with the addition of the specified value. If
+ /// the original set already included the value, then the original set is
+ /// returned and no memory is allocated. The time and space complexity
+ /// of this operation is logarithmic in the size of the original set.
+ /// The memory allocated to represent the set is released when the
+ /// factory object that created the set is destroyed.
ImmutableSet Add(ImmutableSet Old, value_type_ref V) {
return ImmutableSet(F.Add(Old.Root,V));
}
+ /// Remove - Creates a new immutable set that contains all of the values
+ /// of the original set with the exception of the specified value. If
+ /// the original set did not contain the value, the original set is
+ /// returned and no memory is allocated. The time and space complexity
+ /// of this operation is logarithmic in the size of the original set.
+ /// The memory allocated to represent the set is released when the
+ /// factory object that created the set is destroyed.
ImmutableSet Remove(ImmutableSet Old, value_type_ref V) {
return ImmutableSet(F.Remove(Old.Root,V));
}
+ BumpPtrAllocator& getAllocator() { return F.getAllocator(); }
+
private:
Factory(const Factory& RHS) {};
void operator=(const Factory& RHS) {};
};
- friend class Factory;
-
+ friend class Factory;
+
+ /// contains - Returns true if the set contains the specified value.
bool contains(const value_type_ref V) const {
return Root ? Root->contains(V) : false;
}
return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root;
}
+ /// isEmpty - Return true if the set contains no elements.
bool isEmpty() const { return !Root; }
template <typename Callback>
template <typename Callback>
void foreach() { if (Root) { Callback C; Root->foreach(C); } }
+
+ //===--------------------------------------------------===//
+ // Iterators.
+ //===--------------------------------------------------===//
+
+ class iterator {
+ typename TreeTy::iterator itr;
+
+ iterator() {}
+ iterator(TreeTy* t) : itr(t) {}
+ friend class ImmutableSet<ValT,ValInfo>;
+ public:
+ inline value_type_ref operator*() const { return itr->getValue(); }
+ inline iterator& operator++() { ++itr; return *this; }
+ inline iterator operator++(int) { iterator tmp(*this); ++itr; return tmp; }
+ inline iterator& operator--() { --itr; return *this; }
+ inline iterator operator--(int) { iterator tmp(*this); --itr; return tmp; }
+ inline bool operator==(const iterator& RHS) const { return RHS.itr == itr; }
+ inline bool operator!=(const iterator& RHS) const { return RHS.itr != itr; }
+ };
+
+ iterator begin() const { return iterator(Root); }
+ iterator end() const { return iterator(); }
//===--------------------------------------------------===//
// For testing.