Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  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 <cassert>
  19. #include <cstddef>
  20. #include <cstdint>
  21. #include <iterator>
  22. #include <set>
  23.  
  24. namespace llvm {
  25.  
  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< or a
  35. /// comparator is provided).
  36. ///
  37. /// Here is a simple example using integers:
  38. ///
  39. /// \code
  40. ///  EquivalenceClasses<int> EC;
  41. ///  EC.unionSets(1, 2);                // insert 1, 2 into the same set
  42. ///  EC.insert(4); EC.insert(5);        // insert 4, 5 into own sets
  43. ///  EC.unionSets(5, 1);                // merge the set for 1 with 5's set.
  44. ///
  45. ///  for (EquivalenceClasses<int>::iterator I = EC.begin(), E = EC.end();
  46. ///       I != E; ++I) {           // Iterate over all of the equivalence sets.
  47. ///    if (!I->isLeader()) continue;   // Ignore non-leader sets.
  48. ///    for (EquivalenceClasses<int>::member_iterator MI = EC.member_begin(I);
  49. ///         MI != EC.member_end(); ++MI)   // Loop over members in this set.
  50. ///      cerr << *MI << " ";  // Print member.
  51. ///    cerr << "\n";   // Finish set.
  52. ///  }
  53. /// \endcode
  54. ///
  55. /// This example prints:
  56. ///   4
  57. ///   5 1 2
  58. ///
  59. template <class ElemTy, class Compare = std::less<ElemTy>>
  60. class EquivalenceClasses {
  61.   /// ECValue - The EquivalenceClasses data structure is just a set of these.
  62.   /// Each of these represents a relation for a value.  First it stores the
  63.   /// value itself, which provides the ordering that the set queries.  Next, it
  64.   /// provides a "next pointer", which is used to enumerate all of the elements
  65.   /// in the unioned set.  Finally, it defines either a "end of list pointer" or
  66.   /// "leader pointer" depending on whether the value itself is a leader.  A
  67.   /// "leader pointer" points to the node that is the leader for this element,
  68.   /// if the node is not a leader.  A "end of list pointer" points to the last
  69.   /// node in the list of members of this list.  Whether or not a node is a
  70.   /// leader is determined by a bit stolen from one of the pointers.
  71.   class ECValue {
  72.     friend class EquivalenceClasses;
  73.  
  74.     mutable const ECValue *Leader, *Next;
  75.     ElemTy Data;
  76.  
  77.     // ECValue ctor - Start out with EndOfList pointing to this node, Next is
  78.     // Null, isLeader = true.
  79.     ECValue(const ElemTy &Elt)
  80.       : Leader(this), Next((ECValue*)(intptr_t)1), Data(Elt) {}
  81.  
  82.     const ECValue *getLeader() const {
  83.       if (isLeader()) return this;
  84.       if (Leader->isLeader()) return Leader;
  85.       // Path compression.
  86.       return Leader = Leader->getLeader();
  87.     }
  88.  
  89.     const ECValue *getEndOfList() const {
  90.       assert(isLeader() && "Cannot get the end of a list for a non-leader!");
  91.       return Leader;
  92.     }
  93.  
  94.     void setNext(const ECValue *NewNext) const {
  95.       assert(getNext() == nullptr && "Already has a next pointer!");
  96.       Next = (const ECValue*)((intptr_t)NewNext | (intptr_t)isLeader());
  97.     }
  98.  
  99.   public:
  100.     ECValue(const ECValue &RHS) : Leader(this), Next((ECValue*)(intptr_t)1),
  101.                                   Data(RHS.Data) {
  102.       // Only support copying of singleton nodes.
  103.       assert(RHS.isLeader() && RHS.getNext() == nullptr && "Not a singleton!");
  104.     }
  105.  
  106.     bool isLeader() const { return (intptr_t)Next & 1; }
  107.     const ElemTy &getData() const { return Data; }
  108.  
  109.     const ECValue *getNext() const {
  110.       return (ECValue*)((intptr_t)Next & ~(intptr_t)1);
  111.     }
  112.   };
  113.  
  114.   /// A wrapper of the comparator, to be passed to the set.
  115.   struct ECValueComparator {
  116.     using is_transparent = void;
  117.  
  118.     ECValueComparator() : compare(Compare()) {}
  119.  
  120.     bool operator()(const ECValue &lhs, const ECValue &rhs) const {
  121.       return compare(lhs.Data, rhs.Data);
  122.     }
  123.  
  124.     template <typename T>
  125.     bool operator()(const T &lhs, const ECValue &rhs) const {
  126.       return compare(lhs, rhs.Data);
  127.     }
  128.  
  129.     template <typename T>
  130.     bool operator()(const ECValue &lhs, const T &rhs) const {
  131.       return compare(lhs.Data, rhs);
  132.     }
  133.  
  134.     const Compare compare;
  135.   };
  136.  
  137.   /// TheMapping - This implicitly provides a mapping from ElemTy values to the
  138.   /// ECValues, it just keeps the key as part of the value.
  139.   std::set<ECValue, ECValueComparator> TheMapping;
  140.  
  141. public:
  142.   EquivalenceClasses() = default;
  143.   EquivalenceClasses(const EquivalenceClasses &RHS) {
  144.     operator=(RHS);
  145.   }
  146.  
  147.   const EquivalenceClasses &operator=(const EquivalenceClasses &RHS) {
  148.     TheMapping.clear();
  149.     for (iterator I = RHS.begin(), E = RHS.end(); I != E; ++I)
  150.       if (I->isLeader()) {
  151.         member_iterator MI = RHS.member_begin(I);
  152.         member_iterator LeaderIt = member_begin(insert(*MI));
  153.         for (++MI; MI != member_end(); ++MI)
  154.           unionSets(LeaderIt, member_begin(insert(*MI)));
  155.       }
  156.     return *this;
  157.   }
  158.  
  159.   //===--------------------------------------------------------------------===//
  160.   // Inspection methods
  161.   //
  162.  
  163.   /// iterator* - Provides a way to iterate over all values in the set.
  164.   using iterator =
  165.       typename std::set<ECValue, ECValueComparator>::const_iterator;
  166.  
  167.   iterator begin() const { return TheMapping.begin(); }
  168.   iterator end() const { return TheMapping.end(); }
  169.  
  170.   bool empty() const { return TheMapping.empty(); }
  171.  
  172.   /// member_* Iterate over the members of an equivalence class.
  173.   class member_iterator;
  174.   member_iterator member_begin(iterator I) const {
  175.     // Only leaders provide anything to iterate over.
  176.     return member_iterator(I->isLeader() ? &*I : nullptr);
  177.   }
  178.   member_iterator member_end() const {
  179.     return member_iterator(nullptr);
  180.   }
  181.  
  182.   /// findValue - Return an iterator to the specified value.  If it does not
  183.   /// exist, end() is returned.
  184.   iterator findValue(const ElemTy &V) const {
  185.     return TheMapping.find(V);
  186.   }
  187.  
  188.   /// getLeaderValue - Return the leader for the specified value that is in the
  189.   /// set.  It is an error to call this method for a value that is not yet in
  190.   /// the set.  For that, call getOrInsertLeaderValue(V).
  191.   const ElemTy &getLeaderValue(const ElemTy &V) const {
  192.     member_iterator MI = findLeader(V);
  193.     assert(MI != member_end() && "Value is not in the set!");
  194.     return *MI;
  195.   }
  196.  
  197.   /// getOrInsertLeaderValue - Return the leader for the specified value that is
  198.   /// in the set.  If the member is not in the set, it is inserted, then
  199.   /// returned.
  200.   const ElemTy &getOrInsertLeaderValue(const ElemTy &V) {
  201.     member_iterator MI = findLeader(insert(V));
  202.     assert(MI != member_end() && "Value is not in the set!");
  203.     return *MI;
  204.   }
  205.  
  206.   /// getNumClasses - Return the number of equivalence classes in this set.
  207.   /// Note that this is a linear time operation.
  208.   unsigned getNumClasses() const {
  209.     unsigned NC = 0;
  210.     for (iterator I = begin(), E = end(); I != E; ++I)
  211.       if (I->isLeader()) ++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.
  220.   iterator insert(const ElemTy &Data) {
  221.     return TheMapping.insert(ECValue(Data)).first;
  222.   }
  223.  
  224.   /// findLeader - Given a value in the set, return a member iterator for the
  225.   /// equivalence class it is in.  This does the path-compression part that
  226.   /// makes union-find "union findy".  This returns an end iterator if the value
  227.   /// is not in the equivalence class.
  228.   member_iterator findLeader(iterator I) const {
  229.     if (I == TheMapping.end()) return member_end();
  230.     return member_iterator(I->getLeader());
  231.   }
  232.   member_iterator findLeader(const ElemTy &V) const {
  233.     return findLeader(TheMapping.find(V));
  234.   }
  235.  
  236.   /// union - Merge the two equivalence sets for the specified values, inserting
  237.   /// them if they do not already exist in the equivalence set.
  238.   member_iterator unionSets(const ElemTy &V1, const ElemTy &V2) {
  239.     iterator V1I = insert(V1), V2I = insert(V2);
  240.     return unionSets(findLeader(V1I), findLeader(V2I));
  241.   }
  242.   member_iterator unionSets(member_iterator L1, member_iterator L2) {
  243.     assert(L1 != member_end() && L2 != member_end() && "Illegal inputs!");
  244.     if (L1 == L2) return L1;   // Unifying the same two sets, noop.
  245.  
  246.     // Otherwise, this is a real union operation.  Set the end of the L1 list to
  247.     // point to the L2 leader node.
  248.     const ECValue &L1LV = *L1.Node, &L2LV = *L2.Node;
  249.     L1LV.getEndOfList()->setNext(&L2LV);
  250.  
  251.     // Update L1LV's end of list pointer.
  252.     L1LV.Leader = L2LV.getEndOfList();
  253.  
  254.     // Clear L2's leader flag:
  255.     L2LV.Next = L2LV.getNext();
  256.  
  257.     // L2's leader is now L1.
  258.     L2LV.Leader = &L1LV;
  259.     return L1;
  260.   }
  261.  
  262.   // isEquivalent - Return true if V1 is equivalent to V2. This can happen if
  263.   // V1 is equal to V2 or if they belong to one equivalence class.
  264.   bool isEquivalent(const ElemTy &V1, const ElemTy &V2) const {
  265.     // Fast path: any element is equivalent to itself.
  266.     if (V1 == V2)
  267.       return true;
  268.     auto It = findLeader(V1);
  269.     return It != member_end() && It == findLeader(V2);
  270.   }
  271.  
  272.   class member_iterator {
  273.     friend class EquivalenceClasses;
  274.  
  275.     const ECValue *Node;
  276.  
  277.   public:
  278.     using iterator_category = std::forward_iterator_tag;
  279.     using value_type = const ElemTy;
  280.     using size_type = std::size_t;
  281.     using difference_type = std::ptrdiff_t;
  282.     using pointer = value_type *;
  283.     using reference = value_type &;
  284.  
  285.     explicit member_iterator() = default;
  286.     explicit member_iterator(const ECValue *N) : Node(N) {}
  287.  
  288.     reference operator*() const {
  289.       assert(Node != nullptr && "Dereferencing end()!");
  290.       return Node->getData();
  291.     }
  292.     pointer operator->() const { return &operator*(); }
  293.  
  294.     member_iterator &operator++() {
  295.       assert(Node != nullptr && "++'d off the end of the list!");
  296.       Node = Node->getNext();
  297.       return *this;
  298.     }
  299.  
  300.     member_iterator operator++(int) {    // postincrement operators.
  301.       member_iterator tmp = *this;
  302.       ++*this;
  303.       return tmp;
  304.     }
  305.  
  306.     bool operator==(const member_iterator &RHS) const {
  307.       return Node == RHS.Node;
  308.     }
  309.     bool operator!=(const member_iterator &RHS) const {
  310.       return Node != RHS.Node;
  311.     }
  312.   };
  313. };
  314.  
  315. } // end namespace llvm
  316.  
  317. #endif // LLVM_ADT_EQUIVALENCECLASSES_H
  318.