mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01:00
Modified node creation of ImutAVLTree to do a hash lookup for an existing
node in the FoldingSet of nodes held by the Factory object. If we we find a node with a matching hash, we do a full structural comparison. Nodes are also now inserted into the FoldingSet only when we mark them Immutable, as their children can change during intermediate-rebalancing. The 'Profile' method for ImutAVLTree is no longer used when looking up existing ImutAVLTrees with a given set of contents; instead the Profile method is used by other clients that wish to insert such a tree into a folding set. This means that we are not using FoldingSet in ImutAVLTreeFactory in the way it was intended, but instead are using it as an opaque hashtable. llvm-svn: 46717
This commit is contained in:
parent
6dab41ed32
commit
9679f99479
@ -25,8 +25,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 +38,9 @@ public:
|
||||
typedef ImutAVLFactory<ImutInfo> Factory;
|
||||
friend class ImutAVLFactory<ImutInfo>;
|
||||
|
||||
friend class ImutAVLTreeGenericIterator<ImutInfo>;
|
||||
friend class FoldingSet<ImutAVLTree>;
|
||||
|
||||
typedef ImutAVLTreeInOrderIterator<ImutInfo> iterator;
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
@ -103,6 +106,24 @@ public:
|
||||
/// 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
|
||||
// linear in the sizes of the trees.
|
||||
@ -120,14 +141,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;
|
||||
@ -189,6 +203,14 @@ public:
|
||||
return getHeight();
|
||||
}
|
||||
|
||||
/// Profile - Profiling for ImutAVLTree. This is not used by the
|
||||
// Factory object (which internally uses a FoldingSet), but can
|
||||
// be used by external clients that wish to insert an ImutAVLTree
|
||||
// object into a FoldingSet.
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddPointer(this);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// Internal Values.
|
||||
//===----------------------------------------------------===//
|
||||
@ -200,62 +222,6 @@ private:
|
||||
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 (Hash) return Hash;
|
||||
|
||||
unsigned X = ComputeHash(getSafeLeft(), getRight(), getValue());
|
||||
if (!isMutable()) Hash = X;
|
||||
|
||||
return X;
|
||||
}
|
||||
|
||||
/// 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());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// Internal methods (node manipulation; used by Factory).
|
||||
//===----------------------------------------------------===//
|
||||
@ -330,6 +296,33 @@ private:
|
||||
assert (isMutable() && "Only a mutable tree can have its height changed.");
|
||||
Height = h;
|
||||
}
|
||||
|
||||
|
||||
static inline
|
||||
unsigned ComputeHash(ImutAVLTree* L, ImutAVLTree* R, value_type_ref V) {
|
||||
unsigned hash = 0;
|
||||
|
||||
if (L) hash += L->ComputeHash();
|
||||
|
||||
{ // Compute hash of stored data.
|
||||
FoldingSetNodeID ID;
|
||||
ImutInfo::Profile(ID,V);
|
||||
hash += ID.ComputeHash();
|
||||
}
|
||||
|
||||
if (R) hash += R->ComputeHash();
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
inline unsigned ComputeHash() {
|
||||
if (Hash) return Hash;
|
||||
|
||||
unsigned X = ComputeHash(getSafeLeft(), getRight(), getValue());
|
||||
if (!isMutable()) Hash = X;
|
||||
|
||||
return X;
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -390,6 +383,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
|
||||
@ -401,19 +408,55 @@ 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 hash.
|
||||
unsigned hash = TreeTy::ComputeHash(L, R, V);
|
||||
typename CacheTy::bucket_iterator I = Cache.bucket_begin(hash);
|
||||
typename CacheTy::bucket_iterator E = Cache.bucket_end(hash);
|
||||
|
||||
if (TreeTy* T = Cache.FindNodeOrInsertPos(ID,InsertPos))
|
||||
for (; I != E; ++I) {
|
||||
TreeTy* T = &*I;
|
||||
|
||||
if (T->ComputeHash() != hash)
|
||||
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;
|
||||
}
|
||||
|
||||
assert (InsertPos != NULL);
|
||||
// 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>();
|
||||
new (T) TreeTy(L,R,V,IncrementHeight(L,R));
|
||||
Cache.InsertNode(T,InsertPos);
|
||||
|
||||
// We do not insert 'T' into the FoldingSet here. This is because
|
||||
// this tree is still mutable and things may get rebalanced.
|
||||
// Because our hash 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;
|
||||
}
|
||||
@ -546,6 +589,10 @@ private:
|
||||
T->MarkImmutable();
|
||||
MarkImmutable(Left(T));
|
||||
MarkImmutable(Right(T));
|
||||
|
||||
// Now that the node is immutable it can safely be inserted
|
||||
// into the node cache.
|
||||
Cache.InsertNode(T, (void*) &*Cache.bucket_end(T->ComputeHash()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -626,7 +673,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;
|
||||
|
Loading…
Reference in New Issue
Block a user