llvm.org GIT mirror llvm / 72af57f
Rewrite this class, making the following improvements: 1. It now actually uses tarjan's algorithm, so it is a efficient inverse ackerman's function for union operations, not linear time. 2. It now stores one copy of the data in the set instead of two. 3. It now works for elements other than pointers. 4. It now has a more STL-like interface that exposes iterators instead of internal implementation details. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@20677 91177308-0d34-0410-b5e6-96231b3b80d8 Chris Lattner 15 years ago
1 changed file(s) with 198 addition(s) and 88 deletion(s). Raw diff Collapse all Expand all
66 //
77 //===----------------------------------------------------------------------===//
88 //
9 // Generic implementation of equivalence classes and implementation of
10 // union-find algorithms A not-so-fancy implementation: 2 level tree i.e root
11 // and one more level Overhead of a union = size of the equivalence class being
12 // attached Overhead of a find = 1.
9 // Generic implementation of equivalence classes through the use Tarjan's
10 // efficient union-find algorithm.
1311 //
1412 //===----------------------------------------------------------------------===//
1513
1614 #ifndef LLVM_ADT_EQUIVALENCECLASSES_H
1715 #define LLVM_ADT_EQUIVALENCECLASSES_H
1816
19 #include
17 #include "llvm/ADT/iterator"
2018 #include
21 #include
2219
2320 namespace llvm {
2421
22 /// EquivalenceClasses - This represents a collection of equivalence classes and
23 /// supports three efficient operations: insert an element into a class of its
24 /// own, union two classes, and find the class for a given element. In
25 /// addition to these modification methods, it is possible to iterate over all
26 /// of the equivalence classes and all of the elements in a class.
27 ///
28 /// This implementation is an efficient implementation that only stores one copy
29 /// of the element being indexed per entry in the set, and allows any arbitrary
30 /// type to be indexed (as long as it can be ordered with operator<).
31 ///
32 /// Here is a simple example using integers:
33 ///
34 /// EquivalenceClasses EC;
35 /// EC.unionSets(1, 2); // insert 1, 2 into the same set
36 /// EC.insert(4); EC.insert(5); // insert 4, 5 into own sets
37 /// EC.unionSets(5, 1); // merge the set for 1 with 5's set.
38 ///
39 /// for (EquivalenceClasses::iterator I = EC.begin(), E = EC.end();
40 /// I != E; ++I) { // Iterate over all of the equivalence sets.
41 /// if (!I->isLeader()) continue; // Ignore non-leader sets.
42 /// for (EquivalenceClasses::member_iterator MI = EC.member_begin(I);
43 /// MI != EC.member_end(); ++MI) // Loop over members in this set.
44 /// std::cerr << *MI << " "; // Print member.
45 /// std::cerr << "\n"; // Finish set.
46 /// }
47 ///
48 /// This example prints:
49 /// 4
50 /// 5 1 2
51 ///
2552 template
2653 class EquivalenceClasses {
27 // Maps each element to the element that is the leader of its
28 // equivalence class.
29 std::map Elem2LeaderMap;
54 /// ECValue - The EquivalenceClasses data structure is just a set of these.
55 /// Each of these represents a relation for a value. First it stores the
56 /// value itself, which provides the ordering that the set queries. Next, it
57 /// provides a "next pointer", which is used to enumerate all of the elements
58 /// in the unioned set. Finally, it defines either a "end of list pointer" or
59 /// "leader pointer" depending on whether the value itself is a leader. A
60 /// "leader pointer" points to the node that is the leader for this element,
61 /// if the node is not a leader. A "end of list pointer" points to the last
62 /// node in the list of members of this list. Whether or not a node is a
63 /// leader is determined by a bit stolen from one of the pointers.
64 class ECValue {
65 friend class EquivalenceClasses;
66 mutable const ECValue *Leader, *Next;
67 ElemTy Data;
68 // ECValue ctor - Start out with EndOfList pointing to this node, Next is
69 // Null, isLeader = true.
70 ECValue(const ElemTy &Elt)
71 : Leader(this), Next((ECValue*)(intptr_t)1), Data(Elt) {}
72
73 const ECValue *getLeader() const {
74 if (isLeader()) return this;
75 if (Leader->isLeader() == 0) return Leader;
76 // Path compression.
77 return Leader = Leader->getLeader();
78 }
79 const ECValue *getEndOfList() const {
80 assert(isLeader() && "Cannot get the end of a list for a non-leader!");
81 return Leader;
82 }
83
84 void setNext(const ECValue *NewNext) const {
85 assert(getNext() == 0 && "Already has a next pointer!");
86 bool isL = isLeader();
87 Next = (const ECValue*)((intptr_t)NewNext | isLeader());
88 }
89 public:
90 ECValue(const ECValue &RHS) : Leader(this), Next((ECValue*)(intptr_t)1),
91 Data(RHS.Data) {
92 // Only support copying of singleton nodes.
93 assert(RHS.isLeader() && RHS.getNext() == 0 && "Not a singleton!");
94 }
95
96 bool operator<(const ECValue &UFN) const { return Data < UFN.Data; }
97
98 bool isLeader() const { return (intptr_t)Next & 1; }
99 const ElemTy &getData() const { return Data; }
100
101 const ECValue *getNext() const {
102 return (ECValue*)((intptr_t)Next & ~(intptr_t)1);
103 }
104
105 template
106 bool operator<(const T &Val) const { return Data < Val; }
107 };
108
109 /// TheMapping - This implicitly provides a mapping from ElemTy values to the
110 /// ECValues, it just keeps the key as part of the value.
111 std::set TheMapping;
112
113 public:
30114
31 // Maintains the set of leaders
32 std::set LeaderSet;
33
34 // Caches the equivalence class for each leader
35 std::map > LeaderToEqClassMap;
36
37 // Make Element2 the leader of the union of classes Element1 and Element2
38 // Element1 and Element2 are presumed to be leaders of their respective
39 // equivalence classes.
40 void attach(ElemTy Element1, ElemTy Element2) {
41 for (typename std::map::iterator ElemI =
42 Elem2LeaderMap.begin(), ElemE = Elem2LeaderMap.end();
43 ElemI != ElemE; ++ElemI) {
44 if (ElemI->second == Element1)
45 Elem2LeaderMap[ElemI->first] = Element2;
46 }
47 }
48
49 public:
50 // If an element has not yet in any class, make it a separate new class.
51 // Return the leader of the class containing the element.
52 ElemTy addElement (ElemTy NewElement) {
53 typename std::map::iterator ElemI =
54 Elem2LeaderMap.find(NewElement);
55 if (ElemI == Elem2LeaderMap.end()) {
56 Elem2LeaderMap[NewElement] = NewElement;
57 LeaderSet.insert(NewElement);
58 return NewElement;
59 }
60 else
61 return ElemI->second;
62 }
63
64 ElemTy findClass(ElemTy Element) const {
65 typename std::map::const_iterator I =
66 Elem2LeaderMap.find(Element);
67 return (I == Elem2LeaderMap.end())? (ElemTy) 0 : I->second;
68 }
69
70 /// Attach the set with Element1 to the set with Element2 adding Element1 and
71 /// Element2 to the set of equivalence classes if they are not there already.
72 /// Implication: Make Element1 the element in the smaller set.
73 /// Take Leader[Element1] out of the set of leaders.
74 void unionSetsWith(ElemTy Element1, ElemTy Element2) {
75 // If either Element1 or Element2 does not already exist, include it
76 const ElemTy& leader1 = addElement(Element1);
77 const ElemTy& leader2 = addElement(Element2);
78 assert(leader1 != (ElemTy) 0 && leader2 != (ElemTy) 0);
79 if (leader1 != leader2) {
80 attach(leader1, leader2);
81 LeaderSet.erase(leader1);
82 }
83 }
84
85 // Returns a vector containing all the elements in the equivalence class
86 // including Element1
87 const std::set & getEqClass(ElemTy Element1) {
88 assert(Elem2LeaderMap.find(Element1) != Elem2LeaderMap.end());
89 const ElemTy classLeader = Elem2LeaderMap[Element1];
115 //===--------------------------------------------------------------------===//
116 // Inspection methods
117 //
118
119 /// iterator* - Provides a way to iterate over all values in the set.
120 typedef typename std::set::const_iterator iterator;
121 iterator begin() const { return TheMapping.begin(); }
122 iterator end() const { return TheMapping.end(); }
123
124 /// member_* Iterate over the members of an equivalence class.
125 ///
126 class member_iterator;
127 member_iterator member_begin(iterator I) const {
128 // Only leaders provide anything to iterate over.
129 return member_iterator(I->isLeader() ? &*I : 0);
130 }
131 member_iterator member_end() const {
132 return member_iterator(0);
133 }
134
135 //===--------------------------------------------------------------------===//
136 // Mutation methods
137
138 /// insert - Insert a new value into the union/find set, ignoring the request
139 /// if the value already exists.
140 iterator insert(const ElemTy &Data) {
141 return TheMapping.insert(Data).first;
142 }
143
144 /// findLeader - Given a value in the set, return a member iterator for the
145 /// equivalence class it is in. This does the path-compression part that
146 /// makes union-find "union findy". This returns an end iterator if the value
147 /// is not in the equivalence class.
148 ///
149 member_iterator findLeader(iterator I) const {
150 if (I == TheMapping.end()) return member_end();
151 return member_iterator(I->getLeader());
152 }
153 member_iterator findLeader(const ElemTy &V) const {
154 return findLeader(TheMapping.find(V));
155 }
156
157
158 /// union - Merge the two equivalence sets for the specified values, inserting
159 /// them if they do not already exist in the equivalence set.
160 member_iterator unionSets(const ElemTy &V1, const ElemTy &V2) {
161 return unionSets(findLeader(insert(V1)), findLeader(insert(V2)));
162 }
163 member_iterator unionSets(member_iterator L1, member_iterator L2) {
164 assert(L1 != member_end() && L2 != member_end() && "Illegal inputs!");
165 if (L1 == L2) return L1; // Unifying the same two sets, noop.
166
167 // Otherwise, this is a real union operation. Set the end of the L1 list to
168 // point to the L2 leader node.
169 const ECValue &L1LV = *L1.Node, &L2LV = *L2.Node;
170 L1LV.getEndOfList()->setNext(&L2LV);
90171
91 std::set & EqClass = LeaderToEqClassMap[classLeader];
92
93 // If the EqClass vector is empty, it has not been computed yet: do it now
94 if (EqClass.empty()) {
95 for (typename std::map::iterator
96 ElemI = Elem2LeaderMap.begin(), ElemE = Elem2LeaderMap.end();
97 ElemI != ElemE; ++ElemI)
98 if (ElemI->second == classLeader)
99 EqClass.insert(ElemI->first);
100 assert(! EqClass.empty()); // must at least include the leader
101 }
102
103 return EqClass;
104 }
105
106 std::set& getLeaderSet() { return LeaderSet; }
107 const std::set& getLeaderSet() const { return LeaderSet; }
108
109 std::map& getLeaderMap() { return Elem2LeaderMap;}
110 const std::map& getLeaderMap() const { return Elem2LeaderMap;}
172 // Update L1LV's end of list pointer.
173 L1LV.Leader = L2LV.getEndOfList();
174
175 // Clear L2's leader flag:
176 L2LV.Next = L2LV.getNext();
177
178 // L2's leader is now L1.
179 L2LV.Leader = &L1LV;
180 return L1;
181 }
182
183 class member_iterator : public forward_iterator {
184 typedef forward_iterator super;
185 const ECValue *Node;
186 friend class EquivalenceClasses;
187 public:
188 typedef size_t size_type;
189 typedef typename super::pointer pointer;
190 typedef typename super::reference reference;
191
192 explicit member_iterator() {}
193 explicit member_iterator(const ECValue *N) : Node(N) {}
194 member_iterator(const member_iterator &I) : Node(I.Node) {}
195
196 reference operator*() const {
197 assert(Node != 0 && "Dereferencing end()!");
198 return Node->getData();
199 }
200 reference operator->() const { return operator*(); }
201
202 member_iterator &operator++() {
203 assert(Node != 0 && "++'d off the end of the list!");
204 Node = Node->getNext();
205 return *this;
206 }
207
208 member_iterator operator++(int) { // postincrement operators.
209 member_iterator tmp = *this;
210 ++*this;
211 return tmp;
212 }
213
214 bool operator==(const member_iterator &RHS) const {
215 return Node == RHS.Node;
216 }
217 bool operator!=(const member_iterator &RHS) const {
218 return Node != RHS.Node;
219 }
220 };
111221 };
112222
113223 } // End llvm namespace