1 //===-- llvm/ADT/EquivalenceClasses.h - Generic Equiv. Classes --*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Generic implementation of equivalence classes through the use Tarjan's
11 // efficient union-find algorithm.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_ADT_EQUIVALENCECLASSES_H
16 #define LLVM_ADT_EQUIVALENCECLASSES_H
17 
18 #include "llvm/Support/DataTypes.h"
19 #include <cassert>
20 #include <cstddef>
21 #include <set>
22 
23 namespace llvm {
24 
25 /// EquivalenceClasses - This represents a collection of equivalence classes and
26 /// supports three efficient operations: insert an element into a class of its
27 /// own, union two classes, and find the class for a given element.  In
28 /// addition to these modification methods, it is possible to iterate over all
29 /// of the equivalence classes and all of the elements in a class.
30 ///
31 /// This implementation is an efficient implementation that only stores one copy
32 /// of the element being indexed per entry in the set, and allows any arbitrary
33 /// type to be indexed (as long as it can be ordered with operator<).
34 ///
35 /// Here is a simple example using integers:
36 ///
37 /// \code
38 ///  EquivalenceClasses<int> EC;
39 ///  EC.unionSets(1, 2);                // insert 1, 2 into the same set
40 ///  EC.insert(4); EC.insert(5);        // insert 4, 5 into own sets
41 ///  EC.unionSets(5, 1);                // merge the set for 1 with 5's set.
42 ///
43 ///  for (EquivalenceClasses<int>::iterator I = EC.begin(), E = EC.end();
44 ///       I != E; ++I) {           // Iterate over all of the equivalence sets.
45 ///    if (!I->isLeader()) continue;   // Ignore non-leader sets.
46 ///    for (EquivalenceClasses<int>::member_iterator MI = EC.member_begin(I);
47 ///         MI != EC.member_end(); ++MI)   // Loop over members in this set.
48 ///      cerr << *MI << " ";  // Print member.
49 ///    cerr << "\n";   // Finish set.
50 ///  }
51 /// \endcode
52 ///
53 /// This example prints:
54 ///   4
55 ///   5 1 2
56 ///
57 template <class ElemTy>
58 class EquivalenceClasses {
59   /// ECValue - The EquivalenceClasses data structure is just a set of these.
60   /// Each of these represents a relation for a value.  First it stores the
61   /// value itself, which provides the ordering that the set queries.  Next, it
62   /// provides a "next pointer", which is used to enumerate all of the elements
63   /// in the unioned set.  Finally, it defines either a "end of list pointer" or
64   /// "leader pointer" depending on whether the value itself is a leader.  A
65   /// "leader pointer" points to the node that is the leader for this element,
66   /// if the node is not a leader.  A "end of list pointer" points to the last
67   /// node in the list of members of this list.  Whether or not a node is a
68   /// leader is determined by a bit stolen from one of the pointers.
69   class ECValue {
70     friend class EquivalenceClasses;
71     mutable const ECValue *Leader, *Next;
72     ElemTy Data;
73     // ECValue ctor - Start out with EndOfList pointing to this node, Next is
74     // Null, isLeader = true.
ECValue(const ElemTy & Elt)75     ECValue(const ElemTy &Elt)
76       : Leader(this), Next((ECValue*)(intptr_t)1), Data(Elt) {}
77 
getLeader()78     const ECValue *getLeader() const {
79       if (isLeader()) return this;
80       if (Leader->isLeader()) return Leader;
81       // Path compression.
82       return Leader = Leader->getLeader();
83     }
getEndOfList()84     const ECValue *getEndOfList() const {
85       assert(isLeader() && "Cannot get the end of a list for a non-leader!");
86       return Leader;
87     }
88 
setNext(const ECValue * NewNext)89     void setNext(const ECValue *NewNext) const {
90       assert(getNext() == nullptr && "Already has a next pointer!");
91       Next = (const ECValue*)((intptr_t)NewNext | (intptr_t)isLeader());
92     }
93   public:
ECValue(const ECValue & RHS)94     ECValue(const ECValue &RHS) : Leader(this), Next((ECValue*)(intptr_t)1),
95                                   Data(RHS.Data) {
96       // Only support copying of singleton nodes.
97       assert(RHS.isLeader() && RHS.getNext() == nullptr && "Not a singleton!");
98     }
99 
100     bool operator<(const ECValue &UFN) const { return Data < UFN.Data; }
101 
isLeader()102     bool isLeader() const { return (intptr_t)Next & 1; }
getData()103     const ElemTy &getData() const { return Data; }
104 
getNext()105     const ECValue *getNext() const {
106       return (ECValue*)((intptr_t)Next & ~(intptr_t)1);
107     }
108 
109     template<typename T>
110     bool operator<(const T &Val) const { return Data < Val; }
111   };
112 
113   /// TheMapping - This implicitly provides a mapping from ElemTy values to the
114   /// ECValues, it just keeps the key as part of the value.
115   std::set<ECValue> TheMapping;
116 
117 public:
EquivalenceClasses()118   EquivalenceClasses() {}
EquivalenceClasses(const EquivalenceClasses & RHS)119   EquivalenceClasses(const EquivalenceClasses &RHS) {
120     operator=(RHS);
121   }
122 
123   const EquivalenceClasses &operator=(const EquivalenceClasses &RHS) {
124     TheMapping.clear();
125     for (iterator I = RHS.begin(), E = RHS.end(); I != E; ++I)
126       if (I->isLeader()) {
127         member_iterator MI = RHS.member_begin(I);
128         member_iterator LeaderIt = member_begin(insert(*MI));
129         for (++MI; MI != member_end(); ++MI)
130           unionSets(LeaderIt, member_begin(insert(*MI)));
131       }
132     return *this;
133   }
134 
135   //===--------------------------------------------------------------------===//
136   // Inspection methods
137   //
138 
139   /// iterator* - Provides a way to iterate over all values in the set.
140   typedef typename std::set<ECValue>::const_iterator iterator;
begin()141   iterator begin() const { return TheMapping.begin(); }
end()142   iterator end() const { return TheMapping.end(); }
143 
empty()144   bool empty() const { return TheMapping.empty(); }
145 
146   /// member_* Iterate over the members of an equivalence class.
147   ///
148   class member_iterator;
member_begin(iterator I)149   member_iterator member_begin(iterator I) const {
150     // Only leaders provide anything to iterate over.
151     return member_iterator(I->isLeader() ? &*I : nullptr);
152   }
member_end()153   member_iterator member_end() const {
154     return member_iterator(nullptr);
155   }
156 
157   /// findValue - Return an iterator to the specified value.  If it does not
158   /// exist, end() is returned.
findValue(const ElemTy & V)159   iterator findValue(const ElemTy &V) const {
160     return TheMapping.find(V);
161   }
162 
163   /// getLeaderValue - Return the leader for the specified value that is in the
164   /// set.  It is an error to call this method for a value that is not yet in
165   /// the set.  For that, call getOrInsertLeaderValue(V).
getLeaderValue(const ElemTy & V)166   const ElemTy &getLeaderValue(const ElemTy &V) const {
167     member_iterator MI = findLeader(V);
168     assert(MI != member_end() && "Value is not in the set!");
169     return *MI;
170   }
171 
172   /// getOrInsertLeaderValue - Return the leader for the specified value that is
173   /// in the set.  If the member is not in the set, it is inserted, then
174   /// returned.
getOrInsertLeaderValue(const ElemTy & V)175   const ElemTy &getOrInsertLeaderValue(const ElemTy &V) {
176     member_iterator MI = findLeader(insert(V));
177     assert(MI != member_end() && "Value is not in the set!");
178     return *MI;
179   }
180 
181   /// getNumClasses - Return the number of equivalence classes in this set.
182   /// Note that this is a linear time operation.
getNumClasses()183   unsigned getNumClasses() const {
184     unsigned NC = 0;
185     for (iterator I = begin(), E = end(); I != E; ++I)
186       if (I->isLeader()) ++NC;
187     return NC;
188   }
189 
190 
191   //===--------------------------------------------------------------------===//
192   // Mutation methods
193 
194   /// insert - Insert a new value into the union/find set, ignoring the request
195   /// if the value already exists.
insert(const ElemTy & Data)196   iterator insert(const ElemTy &Data) {
197     return TheMapping.insert(ECValue(Data)).first;
198   }
199 
200   /// findLeader - Given a value in the set, return a member iterator for the
201   /// equivalence class it is in.  This does the path-compression part that
202   /// makes union-find "union findy".  This returns an end iterator if the value
203   /// is not in the equivalence class.
204   ///
findLeader(iterator I)205   member_iterator findLeader(iterator I) const {
206     if (I == TheMapping.end()) return member_end();
207     return member_iterator(I->getLeader());
208   }
findLeader(const ElemTy & V)209   member_iterator findLeader(const ElemTy &V) const {
210     return findLeader(TheMapping.find(V));
211   }
212 
213 
214   /// union - Merge the two equivalence sets for the specified values, inserting
215   /// them if they do not already exist in the equivalence set.
unionSets(const ElemTy & V1,const ElemTy & V2)216   member_iterator unionSets(const ElemTy &V1, const ElemTy &V2) {
217     iterator V1I = insert(V1), V2I = insert(V2);
218     return unionSets(findLeader(V1I), findLeader(V2I));
219   }
unionSets(member_iterator L1,member_iterator L2)220   member_iterator unionSets(member_iterator L1, member_iterator L2) {
221     assert(L1 != member_end() && L2 != member_end() && "Illegal inputs!");
222     if (L1 == L2) return L1;   // Unifying the same two sets, noop.
223 
224     // Otherwise, this is a real union operation.  Set the end of the L1 list to
225     // point to the L2 leader node.
226     const ECValue &L1LV = *L1.Node, &L2LV = *L2.Node;
227     L1LV.getEndOfList()->setNext(&L2LV);
228 
229     // Update L1LV's end of list pointer.
230     L1LV.Leader = L2LV.getEndOfList();
231 
232     // Clear L2's leader flag:
233     L2LV.Next = L2LV.getNext();
234 
235     // L2's leader is now L1.
236     L2LV.Leader = &L1LV;
237     return L1;
238   }
239 
240   class member_iterator : public std::iterator<std::forward_iterator_tag,
241                                                const ElemTy, ptrdiff_t> {
242     typedef std::iterator<std::forward_iterator_tag,
243                           const ElemTy, ptrdiff_t> super;
244     const ECValue *Node;
245     friend class EquivalenceClasses;
246   public:
247     typedef size_t size_type;
248     typedef typename super::pointer pointer;
249     typedef typename super::reference reference;
250 
member_iterator()251     explicit member_iterator() {}
member_iterator(const ECValue * N)252     explicit member_iterator(const ECValue *N) : Node(N) {}
253 
254     reference operator*() const {
255       assert(Node != nullptr && "Dereferencing end()!");
256       return Node->getData();
257     }
258     pointer operator->() const { return &operator*(); }
259 
260     member_iterator &operator++() {
261       assert(Node != nullptr && "++'d off the end of the list!");
262       Node = Node->getNext();
263       return *this;
264     }
265 
266     member_iterator operator++(int) {    // postincrement operators.
267       member_iterator tmp = *this;
268       ++*this;
269       return tmp;
270     }
271 
272     bool operator==(const member_iterator &RHS) const {
273       return Node == RHS.Node;
274     }
275     bool operator!=(const member_iterator &RHS) const {
276       return Node != RHS.Node;
277     }
278   };
279 };
280 
281 } // End llvm namespace
282 
283 #endif
284