1 //===--- ImmutableSet.h - Immutable (functional) set interface --*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file defines the ImutAVLTree and ImmutableSet classes.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_ADT_IMMUTABLESET_H
14 #define LLVM_ADT_IMMUTABLESET_H
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/FoldingSet.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/iterator.h"
20 #include "llvm/Support/Allocator.h"
21 #include "llvm/Support/ErrorHandling.h"
31 //===----------------------------------------------------------------------===//
32 // Immutable AVL-Tree Definition.
33 //===----------------------------------------------------------------------===//
35 template <typename ImutInfo
> class ImutAVLFactory
;
36 template <typename ImutInfo
> class ImutIntervalAVLFactory
;
37 template <typename ImutInfo
> class ImutAVLTreeInOrderIterator
;
38 template <typename ImutInfo
> class ImutAVLTreeGenericIterator
;
40 template <typename ImutInfo
>
43 using key_type_ref
= typename
ImutInfo::key_type_ref
;
44 using value_type
= typename
ImutInfo::value_type
;
45 using value_type_ref
= typename
ImutInfo::value_type_ref
;
46 using Factory
= ImutAVLFactory
<ImutInfo
>;
47 using iterator
= ImutAVLTreeInOrderIterator
<ImutInfo
>;
49 friend class ImutAVLFactory
<ImutInfo
>;
50 friend class ImutIntervalAVLFactory
<ImutInfo
>;
51 friend class ImutAVLTreeGenericIterator
<ImutInfo
>;
53 //===----------------------------------------------------===//
55 //===----------------------------------------------------===//
57 /// Return a pointer to the left subtree. This value
58 /// is NULL if there is no left subtree.
59 ImutAVLTree
*getLeft() const { return left
; }
61 /// Return a pointer to the right subtree. This value is
62 /// NULL if there is no right subtree.
63 ImutAVLTree
*getRight() const { return right
; }
65 /// getHeight - Returns the height of the tree. A tree with no subtrees
66 /// has a height of 1.
67 unsigned getHeight() const { return height
; }
69 /// getValue - Returns the data value associated with the tree node.
70 const value_type
& getValue() const { return value
; }
72 /// find - Finds the subtree associated with the specified key value.
73 /// This method returns NULL if no matching subtree is found.
74 ImutAVLTree
* find(key_type_ref K
) {
75 ImutAVLTree
*T
= this;
77 key_type_ref CurrentKey
= ImutInfo::KeyOfValue(T
->getValue());
78 if (ImutInfo::isEqual(K
,CurrentKey
))
80 else if (ImutInfo::isLess(K
,CurrentKey
))
88 /// getMaxElement - Find the subtree associated with the highest ranged
90 ImutAVLTree
* getMaxElement() {
91 ImutAVLTree
*T
= this;
92 ImutAVLTree
*Right
= T
->getRight();
93 while (Right
) { T
= Right
; Right
= T
->getRight(); }
97 /// size - Returns the number of nodes in the tree, which includes
98 /// both leaves and non-leaf nodes.
99 unsigned size() const {
101 if (const ImutAVLTree
* L
= getLeft())
103 if (const ImutAVLTree
* R
= getRight())
108 /// begin - Returns an iterator that iterates over the nodes of the tree
109 /// in an inorder traversal. The returned iterator thus refers to the
110 /// the tree node with the minimum data element.
111 iterator
begin() const { return iterator(this); }
113 /// end - Returns an iterator for the tree that denotes the end of an
114 /// inorder traversal.
115 iterator
end() const { return iterator(); }
117 bool isElementEqual(value_type_ref V
) const {
119 if (!ImutInfo::isEqual(ImutInfo::KeyOfValue(getValue()),
120 ImutInfo::KeyOfValue(V
)))
123 // Also compare the data values.
124 if (!ImutInfo::isDataEqual(ImutInfo::DataOfValue(getValue()),
125 ImutInfo::DataOfValue(V
)))
131 bool isElementEqual(const ImutAVLTree
* RHS
) const {
132 return isElementEqual(RHS
->getValue());
135 /// isEqual - Compares two trees for structural equality and returns true
136 /// if they are equal. This worst case performance of this operation is
137 // linear in the sizes of the trees.
138 bool isEqual(const ImutAVLTree
& RHS
) const {
142 iterator LItr
= begin(), LEnd
= end();
143 iterator RItr
= RHS
.begin(), REnd
= RHS
.end();
145 while (LItr
!= LEnd
&& RItr
!= REnd
) {
146 if (&*LItr
== &*RItr
) {
152 if (!LItr
->isElementEqual(&*RItr
))
159 return LItr
== LEnd
&& RItr
== REnd
;
162 /// isNotEqual - Compares two trees for structural inequality. Performance
163 /// is the same is isEqual.
164 bool isNotEqual(const ImutAVLTree
& RHS
) const { return !isEqual(RHS
); }
166 /// contains - Returns true if this tree contains a subtree (node) that
167 /// has an data element that matches the specified key. Complexity
168 /// is logarithmic in the size of the tree.
169 bool contains(key_type_ref K
) { return (bool) find(K
); }
171 /// foreach - A member template the accepts invokes operator() on a functor
172 /// object (specifed by Callback) for every node/subtree in the tree.
173 /// Nodes are visited using an inorder traversal.
174 template <typename Callback
>
175 void foreach(Callback
& C
) {
176 if (ImutAVLTree
* L
= getLeft())
181 if (ImutAVLTree
* R
= getRight())
185 /// validateTree - A utility method that checks that the balancing and
186 /// ordering invariants of the tree are satisifed. It is a recursive
187 /// method that returns the height of the tree, which is then consumed
188 /// by the enclosing validateTree call. External callers should ignore the
189 /// return value. An invalid tree will cause an assertion to fire in
191 unsigned validateTree() const {
192 unsigned HL
= getLeft() ? getLeft()->validateTree() : 0;
193 unsigned HR
= getRight() ? getRight()->validateTree() : 0;
197 assert(getHeight() == ( HL
> HR
? HL
: HR
) + 1
198 && "Height calculation wrong");
200 assert((HL
> HR
? HL
-HR
: HR
-HL
) <= 2
201 && "Balancing invariant violated");
203 assert((!getLeft() ||
204 ImutInfo::isLess(ImutInfo::KeyOfValue(getLeft()->getValue()),
205 ImutInfo::KeyOfValue(getValue()))) &&
206 "Value in left child is not less that current value");
209 assert(!(getRight() ||
210 ImutInfo::isLess(ImutInfo::KeyOfValue(getValue()),
211 ImutInfo::KeyOfValue(getRight()->getValue()))) &&
212 "Current value is not less that value of right child");
217 //===----------------------------------------------------===//
219 //===----------------------------------------------------===//
225 ImutAVLTree
*prev
= nullptr;
226 ImutAVLTree
*next
= nullptr;
228 unsigned height
: 28;
230 bool IsDigestCached
: 1;
231 bool IsCanonicalized
: 1;
235 uint32_t refCount
= 0;
237 //===----------------------------------------------------===//
238 // Internal methods (node manipulation; used by Factory).
239 //===----------------------------------------------------===//
242 /// ImutAVLTree - Internal constructor that is only called by
244 ImutAVLTree(Factory
*f
, ImutAVLTree
* l
, ImutAVLTree
* r
, value_type_ref v
,
246 : factory(f
), left(l
), right(r
), height(height
), IsMutable(true),
247 IsDigestCached(false), IsCanonicalized(false), value(v
)
249 if (left
) left
->retain();
250 if (right
) right
->retain();
253 /// isMutable - Returns true if the left and right subtree references
254 /// (as well as height) can be changed. If this method returns false,
255 /// the tree is truly immutable. Trees returned from an ImutAVLFactory
256 /// object should always have this method return true. Further, if this
257 /// method returns false for an instance of ImutAVLTree, all subtrees
258 /// will also have this method return false. The converse is not true.
259 bool isMutable() const { return IsMutable
; }
261 /// hasCachedDigest - Returns true if the digest for this tree is cached.
262 /// This can only be true if the tree is immutable.
263 bool hasCachedDigest() const { return IsDigestCached
; }
265 //===----------------------------------------------------===//
266 // Mutating operations. A tree root can be manipulated as
267 // long as its reference has not "escaped" from internal
268 // methods of a factory object (see below). When a tree
269 // pointer is externally viewable by client code, the
270 // internal "mutable bit" is cleared to mark the tree
271 // immutable. Note that a tree that still has its mutable
272 // bit set may have children (subtrees) that are themselves
274 //===----------------------------------------------------===//
276 /// markImmutable - Clears the mutable flag for a tree. After this happens,
277 /// it is an error to call setLeft(), setRight(), and setHeight().
278 void markImmutable() {
279 assert(isMutable() && "Mutable flag already removed.");
283 /// markedCachedDigest - Clears the NoCachedDigest flag for a tree.
284 void markedCachedDigest() {
285 assert(!hasCachedDigest() && "NoCachedDigest flag already removed.");
286 IsDigestCached
= true;
289 /// setHeight - Changes the height of the tree. Used internally by
291 void setHeight(unsigned h
) {
292 assert(isMutable() && "Only a mutable tree can have its height changed.");
296 static uint32_t computeDigest(ImutAVLTree
*L
, ImutAVLTree
*R
,
301 digest
+= L
->computeDigest();
303 // Compute digest of stored data.
305 ImutInfo::Profile(ID
,V
);
306 digest
+= ID
.ComputeHash();
309 digest
+= R
->computeDigest();
314 uint32_t computeDigest() {
315 // Check the lowest bit to determine if digest has actually been
317 if (hasCachedDigest())
320 uint32_t X
= computeDigest(getLeft(), getRight(), getValue());
322 markedCachedDigest();
326 //===----------------------------------------------------===//
327 // Reference count operations.
328 //===----------------------------------------------------===//
331 void retain() { ++refCount
; }
334 assert(refCount
> 0);
344 if (IsCanonicalized
) {
351 factory
->Cache
[factory
->maskCacheIndex(computeDigest())] = next
;
354 // We need to clear the mutability bit in case we are
355 // destroying the node as part of a sweep in ImutAVLFactory::recoverNodes().
357 factory
->freeNodes
.push_back(this);
361 //===----------------------------------------------------------------------===//
362 // Immutable AVL-Tree Factory class.
363 //===----------------------------------------------------------------------===//
365 template <typename ImutInfo
>
366 class ImutAVLFactory
{
367 friend class ImutAVLTree
<ImutInfo
>;
369 using TreeTy
= ImutAVLTree
<ImutInfo
>;
370 using value_type_ref
= typename
TreeTy::value_type_ref
;
371 using key_type_ref
= typename
TreeTy::key_type_ref
;
372 using CacheTy
= DenseMap
<unsigned, TreeTy
*>;
376 std::vector
<TreeTy
*> createdNodes
;
377 std::vector
<TreeTy
*> freeNodes
;
379 bool ownsAllocator() const {
380 return (Allocator
& 0x1) == 0;
383 BumpPtrAllocator
& getAllocator() const {
384 return *reinterpret_cast<BumpPtrAllocator
*>(Allocator
& ~0x1);
387 //===--------------------------------------------------===//
389 //===--------------------------------------------------===//
393 : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {}
395 ImutAVLFactory(BumpPtrAllocator
& Alloc
)
396 : Allocator(reinterpret_cast<uintptr_t>(&Alloc
) | 0x1) {}
399 if (ownsAllocator()) delete &getAllocator();
402 TreeTy
* add(TreeTy
* T
, value_type_ref V
) {
403 T
= add_internal(V
,T
);
409 TreeTy
* remove(TreeTy
* T
, key_type_ref V
) {
410 T
= remove_internal(V
,T
);
416 TreeTy
* getEmptyTree() const { return nullptr; }
419 //===--------------------------------------------------===//
420 // A bunch of quick helper functions used for reasoning
421 // about the properties of trees and their children.
422 // These have succinct names so that the balancing code
423 // is as terse (and readable) as possible.
424 //===--------------------------------------------------===//
426 bool isEmpty(TreeTy
* T
) const { return !T
; }
427 unsigned getHeight(TreeTy
* T
) const { return T
? T
->getHeight() : 0; }
428 TreeTy
* getLeft(TreeTy
* T
) const { return T
->getLeft(); }
429 TreeTy
* getRight(TreeTy
* T
) const { return T
->getRight(); }
430 value_type_ref
getValue(TreeTy
* T
) const { return T
->value
; }
432 // Make sure the index is not the Tombstone or Entry key of the DenseMap.
433 static unsigned maskCacheIndex(unsigned I
) { return (I
& ~0x02); }
435 unsigned incrementHeight(TreeTy
* L
, TreeTy
* R
) const {
436 unsigned hl
= getHeight(L
);
437 unsigned hr
= getHeight(R
);
438 return (hl
> hr
? hl
: hr
) + 1;
441 static bool compareTreeWithSection(TreeTy
* T
,
442 typename
TreeTy::iterator
& TI
,
443 typename
TreeTy::iterator
& TE
) {
444 typename
TreeTy::iterator I
= T
->begin(), E
= T
->end();
445 for ( ; I
!=E
; ++I
, ++TI
) {
446 if (TI
== TE
|| !I
->isElementEqual(&*TI
))
452 //===--------------------------------------------------===//
453 // "createNode" is used to generate new tree roots that link
454 // to other trees. The functon may also simply move links
455 // in an existing root if that root is still marked mutable.
456 // This is necessary because otherwise our balancing code
457 // would leak memory as it would create nodes that are
458 // then discarded later before the finished tree is
459 // returned to the caller.
460 //===--------------------------------------------------===//
462 TreeTy
* createNode(TreeTy
* L
, value_type_ref V
, TreeTy
* R
) {
463 BumpPtrAllocator
& A
= getAllocator();
465 if (!freeNodes
.empty()) {
466 T
= freeNodes
.back();
467 freeNodes
.pop_back();
471 T
= (TreeTy
*) A
.Allocate
<TreeTy
>();
473 new (T
) TreeTy(this, L
, R
, V
, incrementHeight(L
,R
));
474 createdNodes
.push_back(T
);
478 TreeTy
* createNode(TreeTy
* newLeft
, TreeTy
* oldTree
, TreeTy
* newRight
) {
479 return createNode(newLeft
, getValue(oldTree
), newRight
);
482 void recoverNodes() {
483 for (unsigned i
= 0, n
= createdNodes
.size(); i
< n
; ++i
) {
484 TreeTy
*N
= createdNodes
[i
];
485 if (N
->isMutable() && N
->refCount
== 0)
488 createdNodes
.clear();
491 /// balanceTree - Used by add_internal and remove_internal to
492 /// balance a newly created tree.
493 TreeTy
* balanceTree(TreeTy
* L
, value_type_ref V
, TreeTy
* R
) {
494 unsigned hl
= getHeight(L
);
495 unsigned hr
= getHeight(R
);
498 assert(!isEmpty(L
) && "Left tree cannot be empty to have a height >= 2");
500 TreeTy
*LL
= getLeft(L
);
501 TreeTy
*LR
= getRight(L
);
503 if (getHeight(LL
) >= getHeight(LR
))
504 return createNode(LL
, L
, createNode(LR
,V
,R
));
506 assert(!isEmpty(LR
) && "LR cannot be empty because it has a height >= 1");
508 TreeTy
*LRL
= getLeft(LR
);
509 TreeTy
*LRR
= getRight(LR
);
511 return createNode(createNode(LL
,L
,LRL
), LR
, createNode(LRR
,V
,R
));
515 assert(!isEmpty(R
) && "Right tree cannot be empty to have a height >= 2");
517 TreeTy
*RL
= getLeft(R
);
518 TreeTy
*RR
= getRight(R
);
520 if (getHeight(RR
) >= getHeight(RL
))
521 return createNode(createNode(L
,V
,RL
), R
, RR
);
523 assert(!isEmpty(RL
) && "RL cannot be empty because it has a height >= 1");
525 TreeTy
*RLL
= getLeft(RL
);
526 TreeTy
*RLR
= getRight(RL
);
528 return createNode(createNode(L
,V
,RLL
), RL
, createNode(RLR
,R
,RR
));
531 return createNode(L
,V
,R
);
534 /// add_internal - Creates a new tree that includes the specified
535 /// data and the data from the original tree. If the original tree
536 /// already contained the data item, the original tree is returned.
537 TreeTy
* add_internal(value_type_ref V
, TreeTy
* T
) {
539 return createNode(T
, V
, T
);
540 assert(!T
->isMutable());
542 key_type_ref K
= ImutInfo::KeyOfValue(V
);
543 key_type_ref KCurrent
= ImutInfo::KeyOfValue(getValue(T
));
545 if (ImutInfo::isEqual(K
,KCurrent
))
546 return createNode(getLeft(T
), V
, getRight(T
));
547 else if (ImutInfo::isLess(K
,KCurrent
))
548 return balanceTree(add_internal(V
, getLeft(T
)), getValue(T
), getRight(T
));
550 return balanceTree(getLeft(T
), getValue(T
), add_internal(V
, getRight(T
)));
553 /// remove_internal - Creates a new tree that includes all the data
554 /// from the original tree except the specified data. If the
555 /// specified data did not exist in the original tree, the original
556 /// tree is returned.
557 TreeTy
* remove_internal(key_type_ref K
, TreeTy
* T
) {
561 assert(!T
->isMutable());
563 key_type_ref KCurrent
= ImutInfo::KeyOfValue(getValue(T
));
565 if (ImutInfo::isEqual(K
,KCurrent
)) {
566 return combineTrees(getLeft(T
), getRight(T
));
567 } else if (ImutInfo::isLess(K
,KCurrent
)) {
568 return balanceTree(remove_internal(K
, getLeft(T
)),
569 getValue(T
), getRight(T
));
571 return balanceTree(getLeft(T
), getValue(T
),
572 remove_internal(K
, getRight(T
)));
576 TreeTy
* combineTrees(TreeTy
* L
, TreeTy
* R
) {
582 TreeTy
* newRight
= removeMinBinding(R
,OldNode
);
583 return balanceTree(L
, getValue(OldNode
), newRight
);
586 TreeTy
* removeMinBinding(TreeTy
* T
, TreeTy
*& Noderemoved
) {
588 if (isEmpty(getLeft(T
))) {
592 return balanceTree(removeMinBinding(getLeft(T
), Noderemoved
),
593 getValue(T
), getRight(T
));
596 /// markImmutable - Clears the mutable bits of a root and all of its
598 void markImmutable(TreeTy
* T
) {
599 if (!T
|| !T
->isMutable())
602 markImmutable(getLeft(T
));
603 markImmutable(getRight(T
));
607 TreeTy
*getCanonicalTree(TreeTy
*TNew
) {
611 if (TNew
->IsCanonicalized
)
614 // Search the hashtable for another tree with the same digest, and
615 // if find a collision compare those trees by their contents.
616 unsigned digest
= TNew
->computeDigest();
617 TreeTy
*&entry
= Cache
[maskCacheIndex(digest
)];
621 for (TreeTy
*T
= entry
; T
!= nullptr; T
= T
->next
) {
622 // Compare the Contents('T') with Contents('TNew')
623 typename
TreeTy::iterator TI
= T
->begin(), TE
= T
->end();
624 if (!compareTreeWithSection(TNew
, TI
, TE
))
627 continue; // T has more contents than TNew.
628 // Trees did match! Return 'T'.
629 if (TNew
->refCount
== 0)
639 TNew
->IsCanonicalized
= true;
644 //===----------------------------------------------------------------------===//
645 // Immutable AVL-Tree Iterators.
646 //===----------------------------------------------------------------------===//
648 template <typename ImutInfo
>
649 class ImutAVLTreeGenericIterator
650 : public std::iterator
<std::bidirectional_iterator_tag
,
651 ImutAVLTree
<ImutInfo
>> {
652 SmallVector
<uintptr_t,20> stack
;
655 enum VisitFlag
{ VisitedNone
=0x0, VisitedLeft
=0x1, VisitedRight
=0x3,
658 using TreeTy
= ImutAVLTree
<ImutInfo
>;
660 ImutAVLTreeGenericIterator() = default;
661 ImutAVLTreeGenericIterator(const TreeTy
*Root
) {
662 if (Root
) stack
.push_back(reinterpret_cast<uintptr_t>(Root
));
665 TreeTy
&operator*() const {
666 assert(!stack
.empty());
667 return *reinterpret_cast<TreeTy
*>(stack
.back() & ~Flags
);
669 TreeTy
*operator->() const { return &*this; }
671 uintptr_t getVisitState() const {
672 assert(!stack
.empty());
673 return stack
.back() & Flags
;
676 bool atEnd() const { return stack
.empty(); }
678 bool atBeginning() const {
679 return stack
.size() == 1 && getVisitState() == VisitedNone
;
682 void skipToParent() {
683 assert(!stack
.empty());
687 switch (getVisitState()) {
689 stack
.back() |= VisitedLeft
;
692 stack
.back() |= VisitedRight
;
695 llvm_unreachable("Unreachable.");
699 bool operator==(const ImutAVLTreeGenericIterator
&x
) const {
700 return stack
== x
.stack
;
703 bool operator!=(const ImutAVLTreeGenericIterator
&x
) const {
704 return !(*this == x
);
707 ImutAVLTreeGenericIterator
&operator++() {
708 assert(!stack
.empty());
709 TreeTy
* Current
= reinterpret_cast<TreeTy
*>(stack
.back() & ~Flags
);
711 switch (getVisitState()) {
713 if (TreeTy
* L
= Current
->getLeft())
714 stack
.push_back(reinterpret_cast<uintptr_t>(L
));
716 stack
.back() |= VisitedLeft
;
719 if (TreeTy
* R
= Current
->getRight())
720 stack
.push_back(reinterpret_cast<uintptr_t>(R
));
722 stack
.back() |= VisitedRight
;
728 llvm_unreachable("Unreachable.");
733 ImutAVLTreeGenericIterator
&operator--() {
734 assert(!stack
.empty());
735 TreeTy
* Current
= reinterpret_cast<TreeTy
*>(stack
.back() & ~Flags
);
737 switch (getVisitState()) {
742 stack
.back() &= ~Flags
; // Set state to "VisitedNone."
743 if (TreeTy
* L
= Current
->getLeft())
744 stack
.push_back(reinterpret_cast<uintptr_t>(L
) | VisitedRight
);
747 stack
.back() &= ~Flags
;
748 stack
.back() |= VisitedLeft
;
749 if (TreeTy
* R
= Current
->getRight())
750 stack
.push_back(reinterpret_cast<uintptr_t>(R
) | VisitedRight
);
753 llvm_unreachable("Unreachable.");
759 template <typename ImutInfo
>
760 class ImutAVLTreeInOrderIterator
761 : public std::iterator
<std::bidirectional_iterator_tag
,
762 ImutAVLTree
<ImutInfo
>> {
763 using InternalIteratorTy
= ImutAVLTreeGenericIterator
<ImutInfo
>;
765 InternalIteratorTy InternalItr
;
768 using TreeTy
= ImutAVLTree
<ImutInfo
>;
770 ImutAVLTreeInOrderIterator(const TreeTy
* Root
) : InternalItr(Root
) {
772 ++*this; // Advance to first element.
775 ImutAVLTreeInOrderIterator() : InternalItr() {}
777 bool operator==(const ImutAVLTreeInOrderIterator
&x
) const {
778 return InternalItr
== x
.InternalItr
;
781 bool operator!=(const ImutAVLTreeInOrderIterator
&x
) const {
782 return !(*this == x
);
785 TreeTy
&operator*() const { return *InternalItr
; }
786 TreeTy
*operator->() const { return &*InternalItr
; }
788 ImutAVLTreeInOrderIterator
&operator++() {
790 while (!InternalItr
.atEnd() &&
791 InternalItr
.getVisitState() != InternalIteratorTy::VisitedLeft
);
796 ImutAVLTreeInOrderIterator
&operator--() {
798 while (!InternalItr
.atBeginning() &&
799 InternalItr
.getVisitState() != InternalIteratorTy::VisitedLeft
);
805 InternalItr
.skipToParent();
807 while (!InternalItr
.atEnd() &&
808 InternalItr
.getVisitState() != InternalIteratorTy::VisitedLeft
)
813 /// Generic iterator that wraps a T::TreeTy::iterator and exposes
814 /// iterator::getValue() on dereference.
815 template <typename T
>
816 struct ImutAVLValueIterator
817 : iterator_adaptor_base
<
818 ImutAVLValueIterator
<T
>, typename
T::TreeTy::iterator
,
819 typename
std::iterator_traits
<
820 typename
T::TreeTy::iterator
>::iterator_category
,
821 const typename
T::value_type
> {
822 ImutAVLValueIterator() = default;
823 explicit ImutAVLValueIterator(typename
T::TreeTy
*Tree
)
824 : ImutAVLValueIterator::iterator_adaptor_base(Tree
) {}
826 typename
ImutAVLValueIterator::reference
operator*() const {
827 return this->I
->getValue();
831 //===----------------------------------------------------------------------===//
832 // Trait classes for Profile information.
833 //===----------------------------------------------------------------------===//
835 /// Generic profile template. The default behavior is to invoke the
836 /// profile method of an object. Specializations for primitive integers
837 /// and generic handling of pointers is done below.
838 template <typename T
>
839 struct ImutProfileInfo
{
840 using value_type
= const T
;
841 using value_type_ref
= const T
&;
843 static void Profile(FoldingSetNodeID
&ID
, value_type_ref X
) {
844 FoldingSetTrait
<T
>::Profile(X
,ID
);
848 /// Profile traits for integers.
849 template <typename T
>
850 struct ImutProfileInteger
{
851 using value_type
= const T
;
852 using value_type_ref
= const T
&;
854 static void Profile(FoldingSetNodeID
&ID
, value_type_ref X
) {
859 #define PROFILE_INTEGER_INFO(X)\
860 template<> struct ImutProfileInfo<X> : ImutProfileInteger<X> {};
862 PROFILE_INTEGER_INFO(char)
863 PROFILE_INTEGER_INFO(unsigned char)
864 PROFILE_INTEGER_INFO(short)
865 PROFILE_INTEGER_INFO(unsigned short)
866 PROFILE_INTEGER_INFO(unsigned)
867 PROFILE_INTEGER_INFO(signed)
868 PROFILE_INTEGER_INFO(long)
869 PROFILE_INTEGER_INFO(unsigned long)
870 PROFILE_INTEGER_INFO(long long)
871 PROFILE_INTEGER_INFO(unsigned long long)
873 #undef PROFILE_INTEGER_INFO
875 /// Profile traits for booleans.
877 struct ImutProfileInfo
<bool> {
878 using value_type
= const bool;
879 using value_type_ref
= const bool&;
881 static void Profile(FoldingSetNodeID
&ID
, value_type_ref X
) {
886 /// Generic profile trait for pointer types. We treat pointers as
887 /// references to unique objects.
888 template <typename T
>
889 struct ImutProfileInfo
<T
*> {
890 using value_type
= const T
*;
891 using value_type_ref
= value_type
;
893 static void Profile(FoldingSetNodeID
&ID
, value_type_ref X
) {
898 //===----------------------------------------------------------------------===//
899 // Trait classes that contain element comparison operators and type
900 // definitions used by ImutAVLTree, ImmutableSet, and ImmutableMap. These
901 // inherit from the profile traits (ImutProfileInfo) to include operations
902 // for element profiling.
903 //===----------------------------------------------------------------------===//
905 /// ImutContainerInfo - Generic definition of comparison operations for
906 /// elements of immutable containers that defaults to using
907 /// std::equal_to<> and std::less<> to perform comparison of elements.
908 template <typename T
>
909 struct ImutContainerInfo
: public ImutProfileInfo
<T
> {
910 using value_type
= typename ImutProfileInfo
<T
>::value_type
;
911 using value_type_ref
= typename ImutProfileInfo
<T
>::value_type_ref
;
912 using key_type
= value_type
;
913 using key_type_ref
= value_type_ref
;
914 using data_type
= bool;
915 using data_type_ref
= bool;
917 static key_type_ref
KeyOfValue(value_type_ref D
) { return D
; }
918 static data_type_ref
DataOfValue(value_type_ref
) { return true; }
920 static bool isEqual(key_type_ref LHS
, key_type_ref RHS
) {
921 return std::equal_to
<key_type
>()(LHS
,RHS
);
924 static bool isLess(key_type_ref LHS
, key_type_ref RHS
) {
925 return std::less
<key_type
>()(LHS
,RHS
);
928 static bool isDataEqual(data_type_ref
, data_type_ref
) { return true; }
931 /// ImutContainerInfo - Specialization for pointer values to treat pointers
932 /// as references to unique objects. Pointers are thus compared by
934 template <typename T
>
935 struct ImutContainerInfo
<T
*> : public ImutProfileInfo
<T
*> {
936 using value_type
= typename ImutProfileInfo
<T
*>::value_type
;
937 using value_type_ref
= typename ImutProfileInfo
<T
*>::value_type_ref
;
938 using key_type
= value_type
;
939 using key_type_ref
= value_type_ref
;
940 using data_type
= bool;
941 using data_type_ref
= bool;
943 static key_type_ref
KeyOfValue(value_type_ref D
) { return D
; }
944 static data_type_ref
DataOfValue(value_type_ref
) { return true; }
946 static bool isEqual(key_type_ref LHS
, key_type_ref RHS
) { return LHS
== RHS
; }
948 static bool isLess(key_type_ref LHS
, key_type_ref RHS
) { return LHS
< RHS
; }
950 static bool isDataEqual(data_type_ref
, data_type_ref
) { return true; }
953 //===----------------------------------------------------------------------===//
955 //===----------------------------------------------------------------------===//
957 template <typename ValT
, typename ValInfo
= ImutContainerInfo
<ValT
>>
960 using value_type
= typename
ValInfo::value_type
;
961 using value_type_ref
= typename
ValInfo::value_type_ref
;
962 using TreeTy
= ImutAVLTree
<ValInfo
>;
968 /// Constructs a set from a pointer to a tree root. In general one
969 /// should use a Factory object to create sets instead of directly
970 /// invoking the constructor, but there are cases where make this
971 /// constructor public is useful.
972 explicit ImmutableSet(TreeTy
* R
) : Root(R
) {
973 if (Root
) { Root
->retain(); }
976 ImmutableSet(const ImmutableSet
&X
) : Root(X
.Root
) {
977 if (Root
) { Root
->retain(); }
981 if (Root
) { Root
->release(); }
984 ImmutableSet
&operator=(const ImmutableSet
&X
) {
985 if (Root
!= X
.Root
) {
986 if (X
.Root
) { X
.Root
->retain(); }
987 if (Root
) { Root
->release(); }
994 typename
TreeTy::Factory F
;
995 const bool Canonicalize
;
998 Factory(bool canonicalize
= true)
999 : Canonicalize(canonicalize
) {}
1001 Factory(BumpPtrAllocator
& Alloc
, bool canonicalize
= true)
1002 : F(Alloc
), Canonicalize(canonicalize
) {}
1004 Factory(const Factory
& RHS
) = delete;
1005 void operator=(const Factory
& RHS
) = delete;
1007 /// getEmptySet - Returns an immutable set that contains no elements.
1008 ImmutableSet
getEmptySet() {
1009 return ImmutableSet(F
.getEmptyTree());
1012 /// add - Creates a new immutable set that contains all of the values
1013 /// of the original set with the addition of the specified value. If
1014 /// the original set already included the value, then the original set is
1015 /// returned and no memory is allocated. The time and space complexity
1016 /// of this operation is logarithmic in the size of the original set.
1017 /// The memory allocated to represent the set is released when the
1018 /// factory object that created the set is destroyed.
1019 LLVM_NODISCARD ImmutableSet
add(ImmutableSet Old
, value_type_ref V
) {
1020 TreeTy
*NewT
= F
.add(Old
.Root
, V
);
1021 return ImmutableSet(Canonicalize
? F
.getCanonicalTree(NewT
) : NewT
);
1024 /// remove - Creates a new immutable set that contains all of the values
1025 /// of the original set with the exception of the specified value. If
1026 /// the original set did not contain the value, the original set is
1027 /// returned and no memory is allocated. The time and space complexity
1028 /// of this operation is logarithmic in the size of the original set.
1029 /// The memory allocated to represent the set is released when the
1030 /// factory object that created the set is destroyed.
1031 LLVM_NODISCARD ImmutableSet
remove(ImmutableSet Old
, value_type_ref V
) {
1032 TreeTy
*NewT
= F
.remove(Old
.Root
, V
);
1033 return ImmutableSet(Canonicalize
? F
.getCanonicalTree(NewT
) : NewT
);
1036 BumpPtrAllocator
& getAllocator() { return F
.getAllocator(); }
1038 typename
TreeTy::Factory
*getTreeFactory() const {
1039 return const_cast<typename
TreeTy::Factory
*>(&F
);
1043 friend class Factory
;
1045 /// Returns true if the set contains the specified value.
1046 bool contains(value_type_ref V
) const {
1047 return Root
? Root
->contains(V
) : false;
1050 bool operator==(const ImmutableSet
&RHS
) const {
1051 return Root
&& RHS
.Root
? Root
->isEqual(*RHS
.Root
) : Root
== RHS
.Root
;
1054 bool operator!=(const ImmutableSet
&RHS
) const {
1055 return Root
&& RHS
.Root
? Root
->isNotEqual(*RHS
.Root
) : Root
!= RHS
.Root
;
1059 if (Root
) { Root
->retain(); }
1063 TreeTy
*getRootWithoutRetain() const {
1067 /// isEmpty - Return true if the set contains no elements.
1068 bool isEmpty() const { return !Root
; }
1070 /// isSingleton - Return true if the set contains exactly one element.
1071 /// This method runs in constant time.
1072 bool isSingleton() const { return getHeight() == 1; }
1074 template <typename Callback
>
1075 void foreach(Callback
& C
) { if (Root
) Root
->foreach(C
); }
1077 template <typename Callback
>
1078 void foreach() { if (Root
) { Callback C
; Root
->foreach(C
); } }
1080 //===--------------------------------------------------===//
1082 //===--------------------------------------------------===//
1084 using iterator
= ImutAVLValueIterator
<ImmutableSet
>;
1086 iterator
begin() const { return iterator(Root
); }
1087 iterator
end() const { return iterator(); }
1089 //===--------------------------------------------------===//
1091 //===--------------------------------------------------===//
1093 unsigned getHeight() const { return Root
? Root
->getHeight() : 0; }
1095 static void Profile(FoldingSetNodeID
&ID
, const ImmutableSet
&S
) {
1096 ID
.AddPointer(S
.Root
);
1099 void Profile(FoldingSetNodeID
&ID
) const { return Profile(ID
, *this); }
1101 //===--------------------------------------------------===//
1103 //===--------------------------------------------------===//
1105 void validateTree() const { if (Root
) Root
->validateTree(); }
1108 // NOTE: This may some day replace the current ImmutableSet.
1109 template <typename ValT
, typename ValInfo
= ImutContainerInfo
<ValT
>>
1110 class ImmutableSetRef
{
1112 using value_type
= typename
ValInfo::value_type
;
1113 using value_type_ref
= typename
ValInfo::value_type_ref
;
1114 using TreeTy
= ImutAVLTree
<ValInfo
>;
1115 using FactoryTy
= typename
TreeTy::Factory
;
1122 /// Constructs a set from a pointer to a tree root. In general one
1123 /// should use a Factory object to create sets instead of directly
1124 /// invoking the constructor, but there are cases where make this
1125 /// constructor public is useful.
1126 explicit ImmutableSetRef(TreeTy
* R
, FactoryTy
*F
)
1129 if (Root
) { Root
->retain(); }
1132 ImmutableSetRef(const ImmutableSetRef
&X
)
1134 Factory(X
.Factory
) {
1135 if (Root
) { Root
->retain(); }
1138 ~ImmutableSetRef() {
1139 if (Root
) { Root
->release(); }
1142 ImmutableSetRef
&operator=(const ImmutableSetRef
&X
) {
1143 if (Root
!= X
.Root
) {
1144 if (X
.Root
) { X
.Root
->retain(); }
1145 if (Root
) { Root
->release(); }
1147 Factory
= X
.Factory
;
1152 static ImmutableSetRef
getEmptySet(FactoryTy
*F
) {
1153 return ImmutableSetRef(0, F
);
1156 ImmutableSetRef
add(value_type_ref V
) {
1157 return ImmutableSetRef(Factory
->add(Root
, V
), Factory
);
1160 ImmutableSetRef
remove(value_type_ref V
) {
1161 return ImmutableSetRef(Factory
->remove(Root
, V
), Factory
);
1164 /// Returns true if the set contains the specified value.
1165 bool contains(value_type_ref V
) const {
1166 return Root
? Root
->contains(V
) : false;
1169 ImmutableSet
<ValT
> asImmutableSet(bool canonicalize
= true) const {
1170 return ImmutableSet
<ValT
>(canonicalize
?
1171 Factory
->getCanonicalTree(Root
) : Root
);
1174 TreeTy
*getRootWithoutRetain() const {
1178 bool operator==(const ImmutableSetRef
&RHS
) const {
1179 return Root
&& RHS
.Root
? Root
->isEqual(*RHS
.Root
) : Root
== RHS
.Root
;
1182 bool operator!=(const ImmutableSetRef
&RHS
) const {
1183 return Root
&& RHS
.Root
? Root
->isNotEqual(*RHS
.Root
) : Root
!= RHS
.Root
;
1186 /// isEmpty - Return true if the set contains no elements.
1187 bool isEmpty() const { return !Root
; }
1189 /// isSingleton - Return true if the set contains exactly one element.
1190 /// This method runs in constant time.
1191 bool isSingleton() const { return getHeight() == 1; }
1193 //===--------------------------------------------------===//
1195 //===--------------------------------------------------===//
1197 using iterator
= ImutAVLValueIterator
<ImmutableSetRef
>;
1199 iterator
begin() const { return iterator(Root
); }
1200 iterator
end() const { return iterator(); }
1202 //===--------------------------------------------------===//
1204 //===--------------------------------------------------===//
1206 unsigned getHeight() const { return Root
? Root
->getHeight() : 0; }
1208 static void Profile(FoldingSetNodeID
&ID
, const ImmutableSetRef
&S
) {
1209 ID
.AddPointer(S
.Root
);
1212 void Profile(FoldingSetNodeID
&ID
) const { return Profile(ID
, *this); }
1214 //===--------------------------------------------------===//
1216 //===--------------------------------------------------===//
1218 void validateTree() const { if (Root
) Root
->validateTree(); }
1221 } // end namespace llvm
1223 #endif // LLVM_ADT_IMMUTABLESET_H