Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:04

0001 //===- llvm/ADT/EquivalenceClasses.h - Generic Equiv. Classes ---*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 ///
0009 /// \file
0010 /// Generic implementation of equivalence classes through the use Tarjan's
0011 /// efficient union-find algorithm.
0012 ///
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_ADT_EQUIVALENCECLASSES_H
0016 #define LLVM_ADT_EQUIVALENCECLASSES_H
0017 
0018 #include <cassert>
0019 #include <cstddef>
0020 #include <cstdint>
0021 #include <iterator>
0022 #include <set>
0023 
0024 namespace llvm {
0025 
0026 /// EquivalenceClasses - This represents a collection of equivalence classes and
0027 /// supports three efficient operations: insert an element into a class of its
0028 /// own, union two classes, and find the class for a given element.  In
0029 /// addition to these modification methods, it is possible to iterate over all
0030 /// of the equivalence classes and all of the elements in a class.
0031 ///
0032 /// This implementation is an efficient implementation that only stores one copy
0033 /// of the element being indexed per entry in the set, and allows any arbitrary
0034 /// type to be indexed (as long as it can be ordered with operator< or a
0035 /// comparator is provided).
0036 ///
0037 /// Here is a simple example using integers:
0038 ///
0039 /// \code
0040 ///  EquivalenceClasses<int> EC;
0041 ///  EC.unionSets(1, 2);                // insert 1, 2 into the same set
0042 ///  EC.insert(4); EC.insert(5);        // insert 4, 5 into own sets
0043 ///  EC.unionSets(5, 1);                // merge the set for 1 with 5's set.
0044 ///
0045 ///  for (EquivalenceClasses<int>::iterator I = EC.begin(), E = EC.end();
0046 ///       I != E; ++I) {           // Iterate over all of the equivalence sets.
0047 ///    if (!I->isLeader()) continue;   // Ignore non-leader sets.
0048 ///    for (EquivalenceClasses<int>::member_iterator MI = EC.member_begin(I);
0049 ///         MI != EC.member_end(); ++MI)   // Loop over members in this set.
0050 ///      cerr << *MI << " ";  // Print member.
0051 ///    cerr << "\n";   // Finish set.
0052 ///  }
0053 /// \endcode
0054 ///
0055 /// This example prints:
0056 ///   4
0057 ///   5 1 2
0058 ///
0059 template <class ElemTy, class Compare = std::less<ElemTy>>
0060 class EquivalenceClasses {
0061   /// ECValue - The EquivalenceClasses data structure is just a set of these.
0062   /// Each of these represents a relation for a value.  First it stores the
0063   /// value itself, which provides the ordering that the set queries.  Next, it
0064   /// provides a "next pointer", which is used to enumerate all of the elements
0065   /// in the unioned set.  Finally, it defines either a "end of list pointer" or
0066   /// "leader pointer" depending on whether the value itself is a leader.  A
0067   /// "leader pointer" points to the node that is the leader for this element,
0068   /// if the node is not a leader.  A "end of list pointer" points to the last
0069   /// node in the list of members of this list.  Whether or not a node is a
0070   /// leader is determined by a bit stolen from one of the pointers.
0071   class ECValue {
0072     friend class EquivalenceClasses;
0073 
0074     mutable const ECValue *Leader, *Next;
0075     ElemTy Data;
0076 
0077     // ECValue ctor - Start out with EndOfList pointing to this node, Next is
0078     // Null, isLeader = true.
0079     ECValue(const ElemTy &Elt)
0080       : Leader(this), Next((ECValue*)(intptr_t)1), Data(Elt) {}
0081 
0082     const ECValue *getLeader() const {
0083       if (isLeader()) return this;
0084       if (Leader->isLeader()) return Leader;
0085       // Path compression.
0086       return Leader = Leader->getLeader();
0087     }
0088 
0089     const ECValue *getEndOfList() const {
0090       assert(isLeader() && "Cannot get the end of a list for a non-leader!");
0091       return Leader;
0092     }
0093 
0094     void setNext(const ECValue *NewNext) const {
0095       assert(getNext() == nullptr && "Already has a next pointer!");
0096       Next = (const ECValue*)((intptr_t)NewNext | (intptr_t)isLeader());
0097     }
0098 
0099   public:
0100     ECValue(const ECValue &RHS) : Leader(this), Next((ECValue*)(intptr_t)1),
0101                                   Data(RHS.Data) {
0102       // Only support copying of singleton nodes.
0103       assert(RHS.isLeader() && RHS.getNext() == nullptr && "Not a singleton!");
0104     }
0105 
0106     bool isLeader() const { return (intptr_t)Next & 1; }
0107     const ElemTy &getData() const { return Data; }
0108 
0109     const ECValue *getNext() const {
0110       return (ECValue*)((intptr_t)Next & ~(intptr_t)1);
0111     }
0112   };
0113 
0114   /// A wrapper of the comparator, to be passed to the set.
0115   struct ECValueComparator {
0116     using is_transparent = void;
0117 
0118     ECValueComparator() : compare(Compare()) {}
0119 
0120     bool operator()(const ECValue &lhs, const ECValue &rhs) const {
0121       return compare(lhs.Data, rhs.Data);
0122     }
0123 
0124     template <typename T>
0125     bool operator()(const T &lhs, const ECValue &rhs) const {
0126       return compare(lhs, rhs.Data);
0127     }
0128 
0129     template <typename T>
0130     bool operator()(const ECValue &lhs, const T &rhs) const {
0131       return compare(lhs.Data, rhs);
0132     }
0133 
0134     const Compare compare;
0135   };
0136 
0137   /// TheMapping - This implicitly provides a mapping from ElemTy values to the
0138   /// ECValues, it just keeps the key as part of the value.
0139   std::set<ECValue, ECValueComparator> TheMapping;
0140 
0141 public:
0142   EquivalenceClasses() = default;
0143   EquivalenceClasses(const EquivalenceClasses &RHS) {
0144     operator=(RHS);
0145   }
0146 
0147   const EquivalenceClasses &operator=(const EquivalenceClasses &RHS) {
0148     TheMapping.clear();
0149     for (iterator I = RHS.begin(), E = RHS.end(); I != E; ++I)
0150       if (I->isLeader()) {
0151         member_iterator MI = RHS.member_begin(I);
0152         member_iterator LeaderIt = member_begin(insert(*MI));
0153         for (++MI; MI != member_end(); ++MI)
0154           unionSets(LeaderIt, member_begin(insert(*MI)));
0155       }
0156     return *this;
0157   }
0158 
0159   //===--------------------------------------------------------------------===//
0160   // Inspection methods
0161   //
0162 
0163   /// iterator* - Provides a way to iterate over all values in the set.
0164   using iterator =
0165       typename std::set<ECValue, ECValueComparator>::const_iterator;
0166 
0167   iterator begin() const { return TheMapping.begin(); }
0168   iterator end() const { return TheMapping.end(); }
0169 
0170   bool empty() const { return TheMapping.empty(); }
0171 
0172   /// member_* Iterate over the members of an equivalence class.
0173   class member_iterator;
0174   member_iterator member_begin(iterator I) const {
0175     // Only leaders provide anything to iterate over.
0176     return member_iterator(I->isLeader() ? &*I : nullptr);
0177   }
0178   member_iterator member_end() const {
0179     return member_iterator(nullptr);
0180   }
0181 
0182   /// findValue - Return an iterator to the specified value.  If it does not
0183   /// exist, end() is returned.
0184   iterator findValue(const ElemTy &V) const {
0185     return TheMapping.find(V);
0186   }
0187 
0188   /// getLeaderValue - Return the leader for the specified value that is in the
0189   /// set.  It is an error to call this method for a value that is not yet in
0190   /// the set.  For that, call getOrInsertLeaderValue(V).
0191   const ElemTy &getLeaderValue(const ElemTy &V) const {
0192     member_iterator MI = findLeader(V);
0193     assert(MI != member_end() && "Value is not in the set!");
0194     return *MI;
0195   }
0196 
0197   /// getOrInsertLeaderValue - Return the leader for the specified value that is
0198   /// in the set.  If the member is not in the set, it is inserted, then
0199   /// returned.
0200   const ElemTy &getOrInsertLeaderValue(const ElemTy &V) {
0201     member_iterator MI = findLeader(insert(V));
0202     assert(MI != member_end() && "Value is not in the set!");
0203     return *MI;
0204   }
0205 
0206   /// getNumClasses - Return the number of equivalence classes in this set.
0207   /// Note that this is a linear time operation.
0208   unsigned getNumClasses() const {
0209     unsigned NC = 0;
0210     for (iterator I = begin(), E = end(); I != E; ++I)
0211       if (I->isLeader()) ++NC;
0212     return NC;
0213   }
0214 
0215   //===--------------------------------------------------------------------===//
0216   // Mutation methods
0217 
0218   /// insert - Insert a new value into the union/find set, ignoring the request
0219   /// if the value already exists.
0220   iterator insert(const ElemTy &Data) {
0221     return TheMapping.insert(ECValue(Data)).first;
0222   }
0223 
0224   /// findLeader - Given a value in the set, return a member iterator for the
0225   /// equivalence class it is in.  This does the path-compression part that
0226   /// makes union-find "union findy".  This returns an end iterator if the value
0227   /// is not in the equivalence class.
0228   member_iterator findLeader(iterator I) const {
0229     if (I == TheMapping.end()) return member_end();
0230     return member_iterator(I->getLeader());
0231   }
0232   member_iterator findLeader(const ElemTy &V) const {
0233     return findLeader(TheMapping.find(V));
0234   }
0235 
0236   /// union - Merge the two equivalence sets for the specified values, inserting
0237   /// them if they do not already exist in the equivalence set.
0238   member_iterator unionSets(const ElemTy &V1, const ElemTy &V2) {
0239     iterator V1I = insert(V1), V2I = insert(V2);
0240     return unionSets(findLeader(V1I), findLeader(V2I));
0241   }
0242   member_iterator unionSets(member_iterator L1, member_iterator L2) {
0243     assert(L1 != member_end() && L2 != member_end() && "Illegal inputs!");
0244     if (L1 == L2) return L1;   // Unifying the same two sets, noop.
0245 
0246     // Otherwise, this is a real union operation.  Set the end of the L1 list to
0247     // point to the L2 leader node.
0248     const ECValue &L1LV = *L1.Node, &L2LV = *L2.Node;
0249     L1LV.getEndOfList()->setNext(&L2LV);
0250 
0251     // Update L1LV's end of list pointer.
0252     L1LV.Leader = L2LV.getEndOfList();
0253 
0254     // Clear L2's leader flag:
0255     L2LV.Next = L2LV.getNext();
0256 
0257     // L2's leader is now L1.
0258     L2LV.Leader = &L1LV;
0259     return L1;
0260   }
0261 
0262   // isEquivalent - Return true if V1 is equivalent to V2. This can happen if
0263   // V1 is equal to V2 or if they belong to one equivalence class.
0264   bool isEquivalent(const ElemTy &V1, const ElemTy &V2) const {
0265     // Fast path: any element is equivalent to itself.
0266     if (V1 == V2)
0267       return true;
0268     auto It = findLeader(V1);
0269     return It != member_end() && It == findLeader(V2);
0270   }
0271 
0272   class member_iterator {
0273     friend class EquivalenceClasses;
0274 
0275     const ECValue *Node;
0276 
0277   public:
0278     using iterator_category = std::forward_iterator_tag;
0279     using value_type = const ElemTy;
0280     using size_type = std::size_t;
0281     using difference_type = std::ptrdiff_t;
0282     using pointer = value_type *;
0283     using reference = value_type &;
0284 
0285     explicit member_iterator() = default;
0286     explicit member_iterator(const ECValue *N) : Node(N) {}
0287 
0288     reference operator*() const {
0289       assert(Node != nullptr && "Dereferencing end()!");
0290       return Node->getData();
0291     }
0292     pointer operator->() const { return &operator*(); }
0293 
0294     member_iterator &operator++() {
0295       assert(Node != nullptr && "++'d off the end of the list!");
0296       Node = Node->getNext();
0297       return *this;
0298     }
0299 
0300     member_iterator operator++(int) {    // postincrement operators.
0301       member_iterator tmp = *this;
0302       ++*this;
0303       return tmp;
0304     }
0305 
0306     bool operator==(const member_iterator &RHS) const {
0307       return Node == RHS.Node;
0308     }
0309     bool operator!=(const member_iterator &RHS) const {
0310       return Node != RHS.Node;
0311     }
0312   };
0313 };
0314 
0315 } // end namespace llvm
0316 
0317 #endif // LLVM_ADT_EQUIVALENCECLASSES_H