xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ADT/EquivalenceClasses.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- llvm/ADT/EquivalenceClasses.h - Generic Equiv. Classes ---*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
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/ADT/DenseMap.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/ADT/iterator_range.h"
22 #include "llvm/Support/Allocator.h"
23 #include <cassert>
24 #include <cstddef>
25 #include <cstdint>
26 #include <iterator>
27 
28 namespace llvm {
29 
30 /// EquivalenceClasses - This represents a collection of equivalence classes and
31 /// supports three efficient operations: insert an element into a class of its
32 /// own, union two classes, and find the class for a given element.  In
33 /// addition to these modification methods, it is possible to iterate over all
34 /// of the equivalence classes and all of the elements in a class.
35 ///
36 /// This implementation is an efficient implementation that only stores one copy
37 /// of the element being indexed per entry in the set, and allows any arbitrary
38 /// type to be indexed (as long as it can be implements DenseMapInfo).
39 ///
40 /// Here is a simple example using integers:
41 ///
42 /// \code
43 ///  EquivalenceClasses<int> EC;
44 ///  EC.unionSets(1, 2);                // insert 1, 2 into the same set
45 ///  EC.insert(4); EC.insert(5);        // insert 4, 5 into own sets
46 ///  EC.unionSets(5, 1);                // merge the set for 1 with 5's set.
47 ///
48 ///  for (EquivalenceClasses<int>::iterator I = EC.begin(), E = EC.end();
49 ///       I != E; ++I) {           // Iterate over all of the equivalence sets.
50 ///    if (!I->isLeader()) continue;   // Ignore non-leader sets.
51 ///    for (EquivalenceClasses<int>::member_iterator MI = EC.member_begin(I);
52 ///         MI != EC.member_end(); ++MI)   // Loop over members in this set.
53 ///      cerr << *MI << " ";  // Print member.
54 ///    cerr << "\n";   // Finish set.
55 ///  }
56 /// \endcode
57 ///
58 /// This example prints:
59 ///   4
60 ///   5 1 2
61 ///
62 template <class ElemTy> class EquivalenceClasses {
63 public:
64   /// ECValue - The EquivalenceClasses data structure is just a set of these.
65   /// Each of these represents a relation for a value.  First it stores the
66   /// value itself. Next, it provides a "next pointer", which is used to
67   /// enumerate all of the elements in the unioned set.  Finally, it defines
68   /// either a "end of list pointer" or "leader pointer" depending on whether
69   /// the value itself is a leader. A "leader pointer" points to the node that
70   /// is the leader for this element, if the node is not a leader.  A "end of
71   /// list pointer" points to the last node in the list of members of this list.
72   /// Whether or not a node is a leader is determined by a bit stolen from one
73   /// of the pointers.
74   class ECValue {
75     friend class EquivalenceClasses;
76 
77     mutable const ECValue *Leader, *Next;
78     ElemTy Data;
79 
80     // ECValue ctor - Start out with EndOfList pointing to this node, Next is
81     // Null, isLeader = true.
ECValue(const ElemTy & Elt)82     ECValue(const ElemTy &Elt)
83         : Leader(this),
84           Next(reinterpret_cast<ECValue *>(static_cast<intptr_t>(1))),
85           Data(Elt) {}
86 
getLeader()87     const ECValue *getLeader() const {
88       if (isLeader())
89         return this;
90       if (Leader->isLeader())
91         return Leader;
92       // Path compression.
93       return Leader = Leader->getLeader();
94     }
95 
getEndOfList()96     const ECValue *getEndOfList() const {
97       assert(isLeader() && "Cannot get the end of a list for a non-leader!");
98       return Leader;
99     }
100 
setNext(const ECValue * NewNext)101     void setNext(const ECValue *NewNext) const {
102       assert(getNext() == nullptr && "Already has a next pointer!");
103       Next = reinterpret_cast<const ECValue *>(
104           reinterpret_cast<intptr_t>(NewNext) |
105           static_cast<intptr_t>(isLeader()));
106     }
107 
108   public:
ECValue(const ECValue & RHS)109     ECValue(const ECValue &RHS)
110         : Leader(this),
111           Next(reinterpret_cast<ECValue *>(static_cast<intptr_t>(1))),
112           Data(RHS.Data) {
113       // Only support copying of singleton nodes.
114       assert(RHS.isLeader() && RHS.getNext() == nullptr && "Not a singleton!");
115     }
116 
isLeader()117     bool isLeader() const { return (intptr_t)Next & 1; }
getData()118     const ElemTy &getData() const { return Data; }
119 
getNext()120     const ECValue *getNext() const {
121       return reinterpret_cast<ECValue *>(reinterpret_cast<intptr_t>(Next) &
122                                          ~static_cast<intptr_t>(1));
123     }
124   };
125 
126 private:
127   /// TheMapping - This implicitly provides a mapping from ElemTy values to the
128   /// ECValues, it just keeps the key as part of the value.
129   DenseMap<ElemTy, ECValue *> TheMapping;
130 
131   /// List of all members, used to provide a determinstic iteration order.
132   SmallVector<const ECValue *> Members;
133 
134   mutable BumpPtrAllocator ECValueAllocator;
135 
136 public:
137   EquivalenceClasses() = default;
EquivalenceClasses(const EquivalenceClasses & RHS)138   EquivalenceClasses(const EquivalenceClasses &RHS) { operator=(RHS); }
139 
140   EquivalenceClasses &operator=(const EquivalenceClasses &RHS) {
141     TheMapping.clear();
142     Members.clear();
143     for (const auto &E : RHS)
144       if (E->isLeader()) {
145         member_iterator MI = RHS.member_begin(*E);
146         member_iterator LeaderIt = member_begin(insert(*MI));
147         for (++MI; MI != member_end(); ++MI)
148           unionSets(LeaderIt, member_begin(insert(*MI)));
149       }
150     return *this;
151   }
152 
153   //===--------------------------------------------------------------------===//
154   // Inspection methods
155   //
156 
157   /// iterator* - Provides a way to iterate over all values in the set.
158   using iterator = typename SmallVector<const ECValue *>::const_iterator;
159 
begin()160   iterator begin() const { return Members.begin(); }
end()161   iterator end() const { return Members.end(); }
162 
empty()163   bool empty() const { return TheMapping.empty(); }
164 
165   /// member_* Iterate over the members of an equivalence class.
166   class member_iterator;
member_begin(const ECValue & ECV)167   member_iterator member_begin(const ECValue &ECV) const {
168     // Only leaders provide anything to iterate over.
169     return member_iterator(ECV.isLeader() ? &ECV : nullptr);
170   }
171 
member_end()172   member_iterator member_end() const { return member_iterator(nullptr); }
173 
members(const ECValue & ECV)174   iterator_range<member_iterator> members(const ECValue &ECV) const {
175     return make_range(member_begin(ECV), member_end());
176   }
177 
members(const ElemTy & V)178   iterator_range<member_iterator> members(const ElemTy &V) const {
179     return make_range(findLeader(V), member_end());
180   }
181 
182   /// Returns true if \p V is contained an equivalence class.
contains(const ElemTy & V)183   bool contains(const ElemTy &V) const {
184     return TheMapping.find(V) != TheMapping.end();
185   }
186 
187   /// getLeaderValue - Return the leader for the specified value that is in the
188   /// set.  It is an error to call this method for a value that is not yet in
189   /// the set.  For that, call getOrInsertLeaderValue(V).
getLeaderValue(const ElemTy & V)190   const ElemTy &getLeaderValue(const ElemTy &V) const {
191     member_iterator MI = findLeader(V);
192     assert(MI != member_end() && "Value is not in the set!");
193     return *MI;
194   }
195 
196   /// getOrInsertLeaderValue - Return the leader for the specified value that is
197   /// in the set.  If the member is not in the set, it is inserted, then
198   /// returned.
getOrInsertLeaderValue(const ElemTy & V)199   const ElemTy &getOrInsertLeaderValue(const ElemTy &V) {
200     member_iterator MI = findLeader(insert(V));
201     assert(MI != member_end() && "Value is not in the set!");
202     return *MI;
203   }
204 
205   /// getNumClasses - Return the number of equivalence classes in this set.
206   /// Note that this is a linear time operation.
getNumClasses()207   unsigned getNumClasses() const {
208     unsigned NC = 0;
209     for (const auto &E : *this)
210       if (E->isLeader())
211         ++NC;
212     return NC;
213   }
214 
215   //===--------------------------------------------------------------------===//
216   // Mutation methods
217 
218   /// insert - Insert a new value into the union/find set, ignoring the request
219   /// if the value already exists.
insert(const ElemTy & Data)220   const ECValue &insert(const ElemTy &Data) {
221     auto I = TheMapping.insert({Data, nullptr});
222     if (!I.second)
223       return *I.first->second;
224 
225     auto *ECV = new (ECValueAllocator) ECValue(Data);
226     I.first->second = ECV;
227     Members.push_back(ECV);
228     return *ECV;
229   }
230 
231   /// erase - Erase a value from the union/find set, return "true" if erase
232   /// succeeded, or "false" when the value was not found.
erase(const ElemTy & V)233   bool erase(const ElemTy &V) {
234     if (!TheMapping.contains(V))
235       return false;
236     const ECValue *Cur = TheMapping[V];
237     const ECValue *Next = Cur->getNext();
238     // If the current element is the leader and has a successor element,
239     // update the successor element's 'Leader' field to be the last element,
240     // set the successor element's stolen bit, and set the 'Leader' field of
241     // all other elements in same class to be the successor element.
242     if (Cur->isLeader() && Next) {
243       Next->Leader = Cur->Leader;
244       Next->Next = reinterpret_cast<const ECValue *>(
245           reinterpret_cast<intptr_t>(Next->Next) | static_cast<intptr_t>(1));
246 
247       const ECValue *NewLeader = Next;
248       while ((Next = Next->getNext())) {
249         Next->Leader = NewLeader;
250       }
251     } else if (!Cur->isLeader()) {
252       const ECValue *Leader = findLeader(V).Node;
253       const ECValue *Pre = Leader;
254       while (Pre->getNext() != Cur) {
255         Pre = Pre->getNext();
256       }
257       if (!Next) {
258         // If the current element is the last element(not leader), set the
259         // successor of the current element's predecessor to null, and set
260         // the 'Leader' field of the class leader to the predecessor element.
261         Pre->Next = nullptr;
262         Leader->Leader = Pre;
263       } else {
264         // If the current element is in the middle of class, then simply
265         // connect the predecessor element and the successor element.
266         Pre->Next = reinterpret_cast<const ECValue *>(
267             reinterpret_cast<intptr_t>(Next) |
268             static_cast<intptr_t>(Pre->isLeader()));
269         Next->Leader = Pre;
270       }
271     }
272 
273     // Update 'TheMapping' and 'Members'.
274     assert(TheMapping.contains(V) && "Can't find input in TheMapping!");
275     TheMapping.erase(V);
276     auto I = find(Members, Cur);
277     assert(I != Members.end() && "Can't find input in members!");
278     Members.erase(I);
279     return true;
280   }
281 
282   /// findLeader - Given a value in the set, return a member iterator for the
283   /// equivalence class it is in.  This does the path-compression part that
284   /// makes union-find "union findy".  This returns an end iterator if the value
285   /// is not in the equivalence class.
findLeader(const ElemTy & V)286   member_iterator findLeader(const ElemTy &V) const {
287     auto I = TheMapping.find(V);
288     if (I == TheMapping.end())
289       return member_iterator(nullptr);
290     return findLeader(*I->second);
291   }
findLeader(const ECValue & ECV)292   member_iterator findLeader(const ECValue &ECV) const {
293     return member_iterator(ECV.getLeader());
294   }
295 
296   /// union - Merge the two equivalence sets for the specified values, inserting
297   /// them if they do not already exist in the equivalence set.
unionSets(const ElemTy & V1,const ElemTy & V2)298   member_iterator unionSets(const ElemTy &V1, const ElemTy &V2) {
299     const ECValue &V1I = insert(V1), &V2I = insert(V2);
300     return unionSets(findLeader(V1I), findLeader(V2I));
301   }
unionSets(member_iterator L1,member_iterator L2)302   member_iterator unionSets(member_iterator L1, member_iterator L2) {
303     assert(L1 != member_end() && L2 != member_end() && "Illegal inputs!");
304     if (L1 == L2)
305       return L1; // Unifying the same two sets, noop.
306 
307     // Otherwise, this is a real union operation.  Set the end of the L1 list to
308     // point to the L2 leader node.
309     const ECValue &L1LV = *L1.Node, &L2LV = *L2.Node;
310     L1LV.getEndOfList()->setNext(&L2LV);
311 
312     // Update L1LV's end of list pointer.
313     L1LV.Leader = L2LV.getEndOfList();
314 
315     // Clear L2's leader flag:
316     L2LV.Next = L2LV.getNext();
317 
318     // L2's leader is now L1.
319     L2LV.Leader = &L1LV;
320     return L1;
321   }
322 
323   // isEquivalent - Return true if V1 is equivalent to V2. This can happen if
324   // V1 is equal to V2 or if they belong to one equivalence class.
isEquivalent(const ElemTy & V1,const ElemTy & V2)325   bool isEquivalent(const ElemTy &V1, const ElemTy &V2) const {
326     // Fast path: any element is equivalent to itself.
327     if (V1 == V2)
328       return true;
329     auto It = findLeader(V1);
330     return It != member_end() && It == findLeader(V2);
331   }
332 
333   class member_iterator {
334     friend class EquivalenceClasses;
335 
336     const ECValue *Node;
337 
338   public:
339     using iterator_category = std::forward_iterator_tag;
340     using value_type = const ElemTy;
341     using size_type = std::size_t;
342     using difference_type = std::ptrdiff_t;
343     using pointer = value_type *;
344     using reference = value_type &;
345 
346     explicit member_iterator() = default;
member_iterator(const ECValue * N)347     explicit member_iterator(const ECValue *N) : Node(N) {}
348 
349     reference operator*() const {
350       assert(Node != nullptr && "Dereferencing end()!");
351       return Node->getData();
352     }
353     pointer operator->() const { return &operator*(); }
354 
355     member_iterator &operator++() {
356       assert(Node != nullptr && "++'d off the end of the list!");
357       Node = Node->getNext();
358       return *this;
359     }
360 
361     member_iterator operator++(int) { // postincrement operators.
362       member_iterator tmp = *this;
363       ++*this;
364       return tmp;
365     }
366 
367     bool operator==(const member_iterator &RHS) const {
368       return Node == RHS.Node;
369     }
370     bool operator!=(const member_iterator &RHS) const {
371       return Node != RHS.Node;
372     }
373   };
374 };
375 
376 } // end namespace llvm
377 
378 #endif // LLVM_ADT_EQUIVALENCECLASSES_H
379