14#ifndef LLVM_ADT_IMMUTABLESET_H
15#define LLVM_ADT_IMMUTABLESET_H
41template <
typename ImutInfo,
bool Canonicalize = true>
class ImutAVLFactory;
43template <
typename ImutInfo,
bool Canonicalize = true>
75template <
typename ImutInfo,
bool Canonicalize = true>
99 ImutAVLTree *
getLeft()
const {
return left; }
114 ImutAVLTree *
T =
this;
116 key_type_ref CurrentKey = ImutInfo::KeyOfValue(
T->getValue());
117 if (ImutInfo::isEqual(K,CurrentKey))
119 else if (ImutInfo::isLess(K,CurrentKey))
129 ImutAVLTree *
T =
this;
130 ImutAVLTree *
Right =
T->getRight();
139 if (
const ImutAVLTree* L =
getLeft())
141 if (
const ImutAVLTree* R =
getRight())
157 if (!ImutInfo::isEqual(ImutInfo::KeyOfValue(
getValue()),
158 ImutInfo::KeyOfValue(V)))
162 if (!ImutInfo::isDataEqual(ImutInfo::DataOfValue(
getValue()),
163 ImutInfo::DataOfValue(V)))
183 while (LItr != LEnd && RItr != REnd) {
184 if (&*LItr == &*RItr) {
197 return LItr == LEnd && RItr == REnd;
221 &&
"Height calculation wrong");
223 assert((HL > HR ? HL-HR : HR-HL) <= 2
224 &&
"Balancing invariant violated");
228 ImutInfo::KeyOfValue(
getValue()))) &&
229 "Value in left child is not less that current value");
232 ImutInfo::isLess(ImutInfo::KeyOfValue(
getValue()),
234 "Current value is not less that value of right child");
250 unsigned height : 28;
252 unsigned IsMutable : 1;
254 unsigned IsDigestCached : 1;
256 unsigned IsCanonicalized : 1;
271 : left(l), right(r), height(height), IsMutable(
true),
272 IsDigestCached(
false), IsCanonicalized(
false), value(v), factory(f) {
283 bool isMutable()
const {
return IsMutable; }
287 bool hasCachedDigest()
const {
return IsDigestCached; }
302 void markImmutable() {
303 assert(isMutable() &&
"Mutable flag already removed.");
308 void markedCachedDigest() {
309 assert(!hasCachedDigest() &&
"NoCachedDigest flag already removed.");
310 IsDigestCached =
true;
314 void setHeight(
unsigned h) {
315 assert(isMutable() &&
"Only a mutable tree can have its height changed.");
319 static uint32_t computeDigest(ImutAVLTree *L, ImutAVLTree *R,
324 digest +=
L->computeDigest();
328 ImutInfo::Profile(
ID,V);
329 digest +=
ID.ComputeHash();
332 digest +=
R->computeDigest();
337 uint32_t computeDigest() {
340 if (hasCachedDigest())
341 return digest.Digest;
345 markedCachedDigest();
367 if constexpr (Canonicalize) {
368 if (IsCanonicalized) {
375 factory->Cache[factory->maskCacheIndex(computeDigest())] = this->
Next;
382 factory->freeNodes.push_back(
this);
386template <
typename ImutInfo,
bool Canonicalize>
400template <
typename ImutInfo,
bool Canonicalize>
412 std::vector<TreeTy*> createdNodes;
413 std::vector<TreeTy*> freeNodes;
415 bool ownsAllocator()
const {
416 return (Allocator & 0x1) == 0;
435 if (ownsAllocator())
delete &getAllocator();
438 TreeTy*
add(TreeTy*
T, value_type_ref V) {
454 template <
typename CombineFn>
456 bool KeepUnmatched,
bool SkipShared =
false) {
467 auto KeepFirst = [](
const value_type *L,
468 const value_type *R) ->
const value_type & {
495 TreeTy*
getLeft(TreeTy*
T)
const {
return T->getLeft(); }
497 value_type_ref
getValue(TreeTy*
T)
const {
return T->value; }
505 return (hl > hr ? hl : hr) + 1;
521 if (!freeNodes.empty()) {
522 T = freeNodes.back();
523 freeNodes.pop_back();
527 T = (TreeTy*)
A.Allocate<TreeTy>();
530 createdNodes.push_back(
T);
534 TreeTy*
createNode(TreeTy* newLeft, TreeTy* oldTree, TreeTy* newRight) {
548 if (
N != Result &&
N->refCount == 0)
553 createdNodes.clear();
562 assert(!
isEmpty(L) &&
"Left tree cannot be empty to have a height >= 2");
570 assert(!
isEmpty(LR) &&
"LR cannot be empty because it has a height >= 1");
579 assert(!
isEmpty(R) &&
"Right tree cannot be empty to have a height >= 2");
587 assert(!
isEmpty(RL) &&
"RL cannot be empty because it has a height >= 1");
603 TreeTy *
joinTrees(TreeTy *L, value_type_ref V, TreeTy *R) {
615 const value_type *&Match, TreeTy *&R) {
621 key_type_ref KCurrent = ImutInfo::KeyOfValue(
getValue(
T));
622 if (ImutInfo::isEqual(K, KCurrent)) {
628 Match = &
T->getValue();
629 }
else if (ImutInfo::isLess(K, KCurrent)) {
643 template <
typename CombineFn>
663 template <
typename CombineFn>
665 bool KeepUnmatched,
bool SkipShared) {
670 if (SkipShared &&
A ==
B)
679 const value_type *BMatch;
680 splitLookup(
B, ImutInfo::KeyOfValue(AElem), BL, BMatch, BR);
699 auto NewElem =
Combine(&AElem, BMatch);
701 ImutInfo::isDataEqual(ImutInfo::DataOfValue(NewElem),
702 ImutInfo::DataOfValue(AElem)))
715 key_type_ref K = ImutInfo::KeyOfValue(V);
716 key_type_ref KCurrent = ImutInfo::KeyOfValue(
getValue(
T));
718 if (ImutInfo::isEqual(K, KCurrent)) {
720 if (ImutInfo::isDataEqual(ImutInfo::DataOfValue(V),
729 if (ImutInfo::isLess(K, KCurrent))
751 key_type_ref KCurrent = ImutInfo::KeyOfValue(
getValue(
T));
753 if (ImutInfo::isEqual(K, KCurrent))
758 if (ImutInfo::isLess(K, KCurrent))
792 static_assert(Canonicalize,
793 "getCanonicalTree requires a canonicalizing factory");
797 if (TNew->IsCanonicalized)
802 unsigned digest = TNew->computeDigest();
805 for (TreeTy *
T = entry;
T !=
nullptr;
T =
T->Next) {
813 if (TNew->refCount == 0)
822 TNew->IsCanonicalized =
true;
845template <
typename ImutInfo,
bool Canonicalize>
865 for (;
T;
T =
T->getLeft())
872 for (;
T;
T =
T->getRight())
882 void ascendFromRightChild() {
883 TreeTy *Child = Path.pop_back_val();
884 while (!Path.empty() && Path.back()->getRight() == Child)
885 Child = Path.pop_back_val();
889 void ascendFromLeftChild() {
890 TreeTy *Child = Path.pop_back_val();
891 while (!Path.empty() && Path.back()->getLeft() == Child)
892 Child = Path.pop_back_val();
898 descendToMin(
const_cast<TreeTy *
>(Root));
907 if (Path.empty() || x.Path.empty())
908 return Path.empty() == x.Path.empty();
909 return Path.back() == x.Path.back();
912 return !(*
this == x);
919 assert(!Path.empty() &&
"Incrementing the end iterator");
920 if (
TreeTy *R = Path.back()->getRight())
926 ascendFromRightChild();
931 assert(!Path.empty() &&
"Decrementing the end iterator");
932 if (
TreeTy *L = Path.back()->getLeft())
937 ascendFromLeftChild();
945 assert(!Path.empty() &&
"Skipping past the end iterator");
946 ascendFromRightChild();
955 ImutAVLValueIterator<T>, typename T::TreeTy::iterator,
956 typename std::iterator_traits<
957 typename T::TreeTy::iterator>::iterator_category,
958 const typename T::value_type> {
964 return this->
I->getValue();
996#define PROFILE_INTEGER_INFO(X)\
997template<> struct ImutProfileInfo<X> : ImutProfileInteger<X> {};
1010#undef PROFILE_INTEGER_INFO
1025template <
typename T>
1057 return std::equal_to<key_type>()(
LHS,
RHS);
1061 return std::less<key_type>()(
LHS,
RHS);
1091template <
typename ValT,
typename ValInfo = ImutContainerInfo<ValT>,
1092 bool Canonicalize = true>
1133 TreeTy *NewT = F.add(Old.Root.get(), V);
1134 if constexpr (Canonicalize)
1145 if (
A.Root.get() ==
B.Root.get() ||
B.isEmpty())
1151 if (
A.getHeight() <
B.getHeight())
1153 if constexpr (Canonicalize) {
1172 TreeTy *NewT = F.remove(Old.Root.get(), V);
1173 if constexpr (Canonicalize)
1190 return Root ? Root->contains(V) :
false;
1198 if constexpr (Canonicalize)
1199 return Root ==
RHS.Root;
1201 return Root &&
RHS.Root ? Root->isEqual(*
RHS.Root.get())
1206 if constexpr (Canonicalize)
1207 return Root !=
RHS.Root;
1209 return Root &&
RHS.Root ? Root->isNotEqual(*
RHS.Root.get())
1214 if (Root) { Root->retain(); }
1240 unsigned getHeight()
const {
return Root ? Root->getHeight() : 0; }
1243 ID.AddPointer(S.Root.get());
1256template <
typename ValT,
typename ValInfo = ImutContainerInfo<ValT>,
1257 bool Canonicalize = true>
1290 return Root ? Root->contains(V) :
false;
1295 if constexpr (Canonicalize)
1296 return SetTy(Factory->getCanonicalTree(Root.get()));
1298 return SetTy(Root.get());
1304 return Root &&
RHS.Root ? Root->isEqual(*
RHS.Root.get()) : Root ==
RHS.Root;
1308 return Root &&
RHS.Root ? Root->isNotEqual(*
RHS.Root.get())
1332 unsigned getHeight()
const {
return Root ? Root->getHeight() : 0; }
1335 ID.AddPointer(S.Root.get());
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the BumpPtrAllocator interface.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_PREFERRED_TYPE(T)
\macro LLVM_PREFERRED_TYPE Adjust type of bit-field in debug info.
#define LLVM_NO_UNIQUE_ADDRESS
#define LLVM_ATTRIBUTE_NOINLINE
LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so, mark a method "not for inl...
This file defines the DenseMap class.
This file defines a hash set that can be used to remove duplication of nodes in a graph.
#define PROFILE_INTEGER_INFO(X)
This file defines the RefCountedBase, ThreadSafeRefCountedBase, and IntrusiveRefCntPtr classes.
This file defines the SmallVector class.
This class is used to gather all the unique data bits of a node.
unsigned getHeight() const
bool operator==(const ImmutableSetRef &RHS) const
ImmutableSet< ValT, ValInfo, Canonicalize > asImmutableSet() const
ImutAVLTree< ValInfo, Canonicalize > TreeTy
bool contains(value_type_ref V) const
Returns true if the set contains the specified value.
bool operator!=(const ImmutableSetRef &RHS) const
typename ValInfo::value_type_ref value_type_ref
ImmutableSetRef(TreeTy *R, FactoryTy *F)
Constructs a set from a pointer to a tree root.
void Profile(FoldingSetNodeID &ID) const
bool isEmpty() const
Return true if the set contains no elements.
TreeTy * getRootWithoutRetain() const
void validateTree() const
typename TreeTy::Factory FactoryTy
static ImmutableSetRef getEmptySet(FactoryTy *F)
ImmutableSetRef remove(value_type_ref V)
typename ValInfo::value_type value_type
ImutAVLValueIterator< ImmutableSetRef > iterator
static void Profile(FoldingSetNodeID &ID, const ImmutableSetRef &S)
bool isSingleton() const
Return true if the set contains exactly one element.
ImmutableSetRef add(value_type_ref V)
ImmutableSet unionSets(ImmutableSet A, ImmutableSet B)
Returns the union of A and B, computed in a single traversal that shares subtrees of both operands wh...
Factory(BumpPtrAllocator &Alloc)
void operator=(const Factory &RHS)=delete
ImmutableSet add(ImmutableSet Old, value_type_ref V)
Creates a new immutable set that contains all of the values of the original set with the addition of ...
BumpPtrAllocator & getAllocator()
Factory(const Factory &RHS)=delete
ImmutableSet remove(ImmutableSet Old, value_type_ref V)
Creates a new immutable set that contains all of the values of the original set with the exception of...
ImmutableSet getEmptySet()
Returns an immutable set that contains no elements.
TreeTy::Factory * getTreeFactory() const
TreeTy * getRootWithoutRetain() const
bool isEmpty() const
Return true if the set contains no elements.
bool isSingleton() const
Return true if the set contains exactly one element.
static void Profile(FoldingSetNodeID &ID, const ImmutableSet &S)
bool contains(value_type_ref V) const
Returns true if the set contains the specified value.
ImutAVLTree< ValInfo, Canonicalize > TreeTy
ImmutableSet(TreeTy *R)
Constructs a set from a pointer to a tree root.
bool operator!=(const ImmutableSet &RHS) const
typename ValInfo::value_type_ref value_type_ref
unsigned getHeight() const
ImutAVLValueIterator< ImmutableSet > iterator
bool operator==(const ImmutableSet &RHS) const
Compares two sets for equality.
void validateTree() const
void Profile(FoldingSetNodeID &ID) const
typename ValInfo::value_type value_type
TreeTy * add_internal(value_type_ref V, TreeTy *T)
add_internal - Creates a new tree that includes the specified data and the data from the original tre...
ImutAVLFactory(BumpPtrAllocator &Alloc)
unsigned incrementHeight(TreeTy *L, TreeTy *R) const
TreeTy * remove(TreeTy *T, key_type_ref V)
TreeTy * getLeft(TreeTy *T) const
TreeTy * transformTree(TreeTy *T, CombineFn &Combine, bool FromB)
Rebuilds T with the same shape but each element replaced by Combine applied to it.
TreeTy * mergeTrees(TreeTy *A, TreeTy *B, CombineFn Combine, bool KeepUnmatched, bool SkipShared=false)
Merges A and B in a single traversal, sharing every subtree that the two operands do not overlap.
TreeTy * getEmptyTree() const
TreeTy * createNode(TreeTy *newLeft, TreeTy *oldTree, TreeTy *newRight)
unsigned getHeight(TreeTy *T) const
value_type_ref getValue(TreeTy *T) const
TreeTy * joinTrees(TreeTy *L, value_type_ref V, TreeTy *R)
Combines L and R with the value V (every key in L less than V, every key in R greater) into one balan...
bool isEmpty(TreeTy *T) const
TreeTy * combineTrees(TreeTy *L, TreeTy *R)
TreeTy * balanceTree(TreeTy *L, value_type_ref V, TreeTy *R)
Used by add_internal and remove_internal to balance a newly created tree.
void recoverNodes(TreeTy *Result)
TreeTy * add(TreeTy *T, value_type_ref V)
TreeTy * remove_internal(key_type_ref K, TreeTy *T)
remove_internal - Creates a new tree that includes all the data from the original tree except the spe...
TreeTy * getCanonicalTree(TreeTy *TNew)
TreeTy * removeMinBinding(TreeTy *T, TreeTy *&Noderemoved)
TreeTy * unionTrees(TreeTy *A, TreeTy *B)
Returns the set union of A and B (keeping A's element on matching keys).
void splitLookup(TreeTy *T, key_type_ref K, TreeTy *&L, const value_type *&Match, TreeTy *&R)
Splits T into L (all keys less than K) and R (all keys greater than K).
TreeTy * getRight(TreeTy *T) const
TreeTy * merge_internal(TreeTy *A, TreeTy *B, CombineFn &Combine, bool KeepUnmatched, bool SkipShared)
Merges A and B by recursing over A's structure and splitting B at each of A's keys.
TreeTy * createNode(TreeTy *L, value_type_ref V, TreeTy *R)
static unsigned maskCacheIndex(unsigned I)
Bidirectional in-order iterator over the nodes of an ImutAVLTree.
bool operator!=(const ImutAVLTreeInOrderIterator &x) const
ImutAVLTree< ImutInfo, Canonicalize > value_type
ImutAVLTree< ImutInfo, Canonicalize > TreeTy
ImutAVLTreeInOrderIterator & operator++()
TreeTy & operator*() const
void skipSubTree()
Move to the in-order successor of the entire subtree rooted at the current node, i....
ImutAVLTreeInOrderIterator & operator--()
ImutAVLTreeInOrderIterator()=default
std::ptrdiff_t difference_type
TreeTy * operator->() const
std::bidirectional_iterator_tag iterator_category
bool operator==(const ImutAVLTreeInOrderIterator &x) const
ImutAVLTreeInOrderIterator(const TreeTy *Root)
unsigned getHeight() const
Returns the height of the tree. A tree with no subtrees has a height of 1.
iterator end() const
Returns an iterator for the tree that denotes the end of an inorder traversal.
typename ValInfo::key_type_ref key_type_ref
ImutAVLTreeInOrderIterator< ValInfo, Canonicalize > iterator
ImutAVLTree * find(key_type_ref K)
Finds the subtree associated with the specified key value.
typename ValInfo::value_type value_type
bool isNotEqual(const ImutAVLTree &RHS) const
Compares two trees for structural inequality.
bool contains(key_type_ref K)
Returns true if this tree contains a subtree (node) that has an data element that matches the specifi...
unsigned size() const
Returns the number of nodes in the tree, which includes both leaves and.
ImutAVLTree * getRight() const
Return a pointer to the right subtree.
ImutAVLTree * getMaxElement()
Find the subtree associated with the highest ranged key value.
ImutAVLFactory< ValInfo, Canonicalize > Factory
bool isElementEqual(const ImutAVLTree *RHS) const
LLVM_ATTRIBUTE_NOINLINE void destroy()
bool isEqual(const ImutAVLTree &RHS) const
Compares two trees for structural equality and returns true if they are equal.
unsigned validateTree() const
A utility method that checks that the balancing and ordering invariants of the tree are satisfied.
const value_type & getValue() const
Returns the data value associated with the tree node.
bool isElementEqual(value_type_ref V) const
typename ValInfo::value_type_ref value_type_ref
iterator begin() const
Returns an iterator that iterates over the nodes of the tree in an inorder traversal.
ImutAVLTree * getLeft() const
Return a pointer to the left subtree.
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
iterator_adaptor_base()=default
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This is an optimization pass for GlobalISel generic memory operations.
auto reverse(ContainerTy &&C)
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static void Profile(const T &X, FoldingSetNodeID &ID)
The factory-side canonicalization cache: digest -> tree chain.
DenseMap< unsigned, Tree * > Cache
The cached structural digest, used only for canonicalization.
The intrusive doubly-linked chain of same-digest trees in the factory's canonicalization cache.
Generic iterator that wraps a T::TreeTy::iterator and exposes iterator::getValue() on dereference.
ImutAVLValueIterator()=default
ImutAVLValueIterator::reference operator*() const
ImutAVLValueIterator(typename T::TreeTy *Tree)
static bool isDataEqual(data_type_ref, data_type_ref)
value_type_ref key_type_ref
static key_type_ref KeyOfValue(value_type_ref D)
static bool isEqual(key_type_ref LHS, key_type_ref RHS)
typename ImutProfileInfo< T * >::value_type_ref value_type_ref
typename ImutProfileInfo< T * >::value_type value_type
static data_type_ref DataOfValue(value_type_ref)
static bool isLess(key_type_ref LHS, key_type_ref RHS)
Generic definition of comparison operations for elements of immutable containers that defaults to usi...
static bool isLess(key_type_ref LHS, key_type_ref RHS)
typename ImutProfileInfo< T >::value_type value_type
static bool isEqual(key_type_ref LHS, key_type_ref RHS)
static bool isDataEqual(data_type_ref, data_type_ref)
static data_type_ref DataOfValue(value_type_ref)
static key_type_ref KeyOfValue(value_type_ref D)
value_type_ref key_type_ref
typename ImutProfileInfo< T >::value_type_ref value_type_ref
static void Profile(FoldingSetNodeID &ID, value_type_ref X)
value_type value_type_ref
const bool & value_type_ref
static void Profile(FoldingSetNodeID &ID, value_type_ref X)
Generic profile template.
static void Profile(FoldingSetNodeID &ID, value_type_ref X)
Profile traits for integers.
static void Profile(FoldingSetNodeID &ID, value_type_ref X)
static void retain(ImutAVLTree< ImutInfo, Canonicalize > *Tree)
Class you can specialize to provide custom retain/release functionality for a type.