EquivalenceClasses.h 11 KB

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