Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

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

  1. //===- llvm/ADT/FoldingSet.h - Uniquing Hash Set ----------------*- 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. /// This file defines a hash set that can be used to remove duplication of nodes
  11. /// in a graph.  This code was originally created by Chris Lattner for use with
  12. /// SelectionDAGCSEMap, but was isolated to provide use across the llvm code
  13. /// set.
  14. //===----------------------------------------------------------------------===//
  15.  
  16. #ifndef LLVM_ADT_FOLDINGSET_H
  17. #define LLVM_ADT_FOLDINGSET_H
  18.  
  19. #include "llvm/ADT/Hashing.h"
  20. #include "llvm/ADT/SmallVector.h"
  21. #include "llvm/ADT/iterator.h"
  22. #include "llvm/Support/Allocator.h"
  23. #include <cassert>
  24. #include <cstddef>
  25. #include <cstdint>
  26. #include <type_traits>
  27. #include <utility>
  28.  
  29. namespace llvm {
  30.  
  31. /// This folding set used for two purposes:
  32. ///   1. Given information about a node we want to create, look up the unique
  33. ///      instance of the node in the set.  If the node already exists, return
  34. ///      it, otherwise return the bucket it should be inserted into.
  35. ///   2. Given a node that has already been created, remove it from the set.
  36. ///
  37. /// This class is implemented as a single-link chained hash table, where the
  38. /// "buckets" are actually the nodes themselves (the next pointer is in the
  39. /// node).  The last node points back to the bucket to simplify node removal.
  40. ///
  41. /// Any node that is to be included in the folding set must be a subclass of
  42. /// FoldingSetNode.  The node class must also define a Profile method used to
  43. /// establish the unique bits of data for the node.  The Profile method is
  44. /// passed a FoldingSetNodeID object which is used to gather the bits.  Just
  45. /// call one of the Add* functions defined in the FoldingSetBase::NodeID class.
  46. /// NOTE: That the folding set does not own the nodes and it is the
  47. /// responsibility of the user to dispose of the nodes.
  48. ///
  49. /// Eg.
  50. ///    class MyNode : public FoldingSetNode {
  51. ///    private:
  52. ///      std::string Name;
  53. ///      unsigned Value;
  54. ///    public:
  55. ///      MyNode(const char *N, unsigned V) : Name(N), Value(V) {}
  56. ///       ...
  57. ///      void Profile(FoldingSetNodeID &ID) const {
  58. ///        ID.AddString(Name);
  59. ///        ID.AddInteger(Value);
  60. ///      }
  61. ///      ...
  62. ///    };
  63. ///
  64. /// To define the folding set itself use the FoldingSet template;
  65. ///
  66. /// Eg.
  67. ///    FoldingSet<MyNode> MyFoldingSet;
  68. ///
  69. /// Four public methods are available to manipulate the folding set;
  70. ///
  71. /// 1) If you have an existing node that you want add to the set but unsure
  72. /// that the node might already exist then call;
  73. ///
  74. ///    MyNode *M = MyFoldingSet.GetOrInsertNode(N);
  75. ///
  76. /// If The result is equal to the input then the node has been inserted.
  77. /// Otherwise, the result is the node existing in the folding set, and the
  78. /// input can be discarded (use the result instead.)
  79. ///
  80. /// 2) If you are ready to construct a node but want to check if it already
  81. /// exists, then call FindNodeOrInsertPos with a FoldingSetNodeID of the bits to
  82. /// check;
  83. ///
  84. ///   FoldingSetNodeID ID;
  85. ///   ID.AddString(Name);
  86. ///   ID.AddInteger(Value);
  87. ///   void *InsertPoint;
  88. ///
  89. ///    MyNode *M = MyFoldingSet.FindNodeOrInsertPos(ID, InsertPoint);
  90. ///
  91. /// If found then M will be non-NULL, else InsertPoint will point to where it
  92. /// should be inserted using InsertNode.
  93. ///
  94. /// 3) If you get a NULL result from FindNodeOrInsertPos then you can insert a
  95. /// new node with InsertNode;
  96. ///
  97. ///    MyFoldingSet.InsertNode(M, InsertPoint);
  98. ///
  99. /// 4) Finally, if you want to remove a node from the folding set call;
  100. ///
  101. ///    bool WasRemoved = MyFoldingSet.RemoveNode(M);
  102. ///
  103. /// The result indicates whether the node existed in the folding set.
  104.  
  105. class FoldingSetNodeID;
  106. class StringRef;
  107.  
  108. //===----------------------------------------------------------------------===//
  109. /// FoldingSetBase - Implements the folding set functionality.  The main
  110. /// structure is an array of buckets.  Each bucket is indexed by the hash of
  111. /// the nodes it contains.  The bucket itself points to the nodes contained
  112. /// in the bucket via a singly linked list.  The last node in the list points
  113. /// back to the bucket to facilitate node removal.
  114. ///
  115. class FoldingSetBase {
  116. protected:
  117.   /// Buckets - Array of bucket chains.
  118.   void **Buckets;
  119.  
  120.   /// NumBuckets - Length of the Buckets array.  Always a power of 2.
  121.   unsigned NumBuckets;
  122.  
  123.   /// NumNodes - Number of nodes in the folding set. Growth occurs when NumNodes
  124.   /// is greater than twice the number of buckets.
  125.   unsigned NumNodes;
  126.  
  127.   explicit FoldingSetBase(unsigned Log2InitSize = 6);
  128.   FoldingSetBase(FoldingSetBase &&Arg);
  129.   FoldingSetBase &operator=(FoldingSetBase &&RHS);
  130.   ~FoldingSetBase();
  131.  
  132. public:
  133.   //===--------------------------------------------------------------------===//
  134.   /// Node - This class is used to maintain the singly linked bucket list in
  135.   /// a folding set.
  136.   class Node {
  137.   private:
  138.     // NextInFoldingSetBucket - next link in the bucket list.
  139.     void *NextInFoldingSetBucket = nullptr;
  140.  
  141.   public:
  142.     Node() = default;
  143.  
  144.     // Accessors
  145.     void *getNextInBucket() const { return NextInFoldingSetBucket; }
  146.     void SetNextInBucket(void *N) { NextInFoldingSetBucket = N; }
  147.   };
  148.  
  149.   /// clear - Remove all nodes from the folding set.
  150.   void clear();
  151.  
  152.   /// size - Returns the number of nodes in the folding set.
  153.   unsigned size() const { return NumNodes; }
  154.  
  155.   /// empty - Returns true if there are no nodes in the folding set.
  156.   bool empty() const { return NumNodes == 0; }
  157.  
  158.   /// capacity - Returns the number of nodes permitted in the folding set
  159.   /// before a rebucket operation is performed.
  160.   unsigned capacity() {
  161.     // We allow a load factor of up to 2.0,
  162.     // so that means our capacity is NumBuckets * 2
  163.     return NumBuckets * 2;
  164.   }
  165.  
  166. protected:
  167.   /// Functions provided by the derived class to compute folding properties.
  168.   /// This is effectively a vtable for FoldingSetBase, except that we don't
  169.   /// actually store a pointer to it in the object.
  170.   struct FoldingSetInfo {
  171.     /// GetNodeProfile - Instantiations of the FoldingSet template implement
  172.     /// this function to gather data bits for the given node.
  173.     void (*GetNodeProfile)(const FoldingSetBase *Self, Node *N,
  174.                            FoldingSetNodeID &ID);
  175.  
  176.     /// NodeEquals - Instantiations of the FoldingSet template implement
  177.     /// this function to compare the given node with the given ID.
  178.     bool (*NodeEquals)(const FoldingSetBase *Self, Node *N,
  179.                        const FoldingSetNodeID &ID, unsigned IDHash,
  180.                        FoldingSetNodeID &TempID);
  181.  
  182.     /// ComputeNodeHash - Instantiations of the FoldingSet template implement
  183.     /// this function to compute a hash value for the given node.
  184.     unsigned (*ComputeNodeHash)(const FoldingSetBase *Self, Node *N,
  185.                                 FoldingSetNodeID &TempID);
  186.   };
  187.  
  188. private:
  189.   /// GrowHashTable - Double the size of the hash table and rehash everything.
  190.   void GrowHashTable(const FoldingSetInfo &Info);
  191.  
  192.   /// GrowBucketCount - resize the hash table and rehash everything.
  193.   /// NewBucketCount must be a power of two, and must be greater than the old
  194.   /// bucket count.
  195.   void GrowBucketCount(unsigned NewBucketCount, const FoldingSetInfo &Info);
  196.  
  197. protected:
  198.   // The below methods are protected to encourage subclasses to provide a more
  199.   // type-safe API.
  200.  
  201.   /// reserve - Increase the number of buckets such that adding the
  202.   /// EltCount-th node won't cause a rebucket operation. reserve is permitted
  203.   /// to allocate more space than requested by EltCount.
  204.   void reserve(unsigned EltCount, const FoldingSetInfo &Info);
  205.  
  206.   /// RemoveNode - Remove a node from the folding set, returning true if one
  207.   /// was removed or false if the node was not in the folding set.
  208.   bool RemoveNode(Node *N);
  209.  
  210.   /// GetOrInsertNode - If there is an existing simple Node exactly
  211.   /// equal to the specified node, return it.  Otherwise, insert 'N' and return
  212.   /// it instead.
  213.   Node *GetOrInsertNode(Node *N, const FoldingSetInfo &Info);
  214.  
  215.   /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
  216.   /// return it.  If not, return the insertion token that will make insertion
  217.   /// faster.
  218.   Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos,
  219.                             const FoldingSetInfo &Info);
  220.  
  221.   /// InsertNode - Insert the specified node into the folding set, knowing that
  222.   /// it is not already in the folding set.  InsertPos must be obtained from
  223.   /// FindNodeOrInsertPos.
  224.   void InsertNode(Node *N, void *InsertPos, const FoldingSetInfo &Info);
  225. };
  226.  
  227. //===----------------------------------------------------------------------===//
  228.  
  229. /// DefaultFoldingSetTrait - This class provides default implementations
  230. /// for FoldingSetTrait implementations.
  231. template<typename T> struct DefaultFoldingSetTrait {
  232.   static void Profile(const T &X, FoldingSetNodeID &ID) {
  233.     X.Profile(ID);
  234.   }
  235.   static void Profile(T &X, FoldingSetNodeID &ID) {
  236.     X.Profile(ID);
  237.   }
  238.  
  239.   // Equals - Test if the profile for X would match ID, using TempID
  240.   // to compute a temporary ID if necessary. The default implementation
  241.   // just calls Profile and does a regular comparison. Implementations
  242.   // can override this to provide more efficient implementations.
  243.   static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
  244.                             FoldingSetNodeID &TempID);
  245.  
  246.   // ComputeHash - Compute a hash value for X, using TempID to
  247.   // compute a temporary ID if necessary. The default implementation
  248.   // just calls Profile and does a regular hash computation.
  249.   // Implementations can override this to provide more efficient
  250.   // implementations.
  251.   static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID);
  252. };
  253.  
  254. /// FoldingSetTrait - This trait class is used to define behavior of how
  255. /// to "profile" (in the FoldingSet parlance) an object of a given type.
  256. /// The default behavior is to invoke a 'Profile' method on an object, but
  257. /// through template specialization the behavior can be tailored for specific
  258. /// types.  Combined with the FoldingSetNodeWrapper class, one can add objects
  259. /// to FoldingSets that were not originally designed to have that behavior.
  260. template <typename T, typename Enable = void>
  261. struct FoldingSetTrait : public DefaultFoldingSetTrait<T> {};
  262.  
  263. /// DefaultContextualFoldingSetTrait - Like DefaultFoldingSetTrait, but
  264. /// for ContextualFoldingSets.
  265. template<typename T, typename Ctx>
  266. struct DefaultContextualFoldingSetTrait {
  267.   static void Profile(T &X, FoldingSetNodeID &ID, Ctx Context) {
  268.     X.Profile(ID, Context);
  269.   }
  270.  
  271.   static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
  272.                             FoldingSetNodeID &TempID, Ctx Context);
  273.   static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID,
  274.                                      Ctx Context);
  275. };
  276.  
  277. /// ContextualFoldingSetTrait - Like FoldingSetTrait, but for
  278. /// ContextualFoldingSets.
  279. template<typename T, typename Ctx> struct ContextualFoldingSetTrait
  280.   : public DefaultContextualFoldingSetTrait<T, Ctx> {};
  281.  
  282. //===--------------------------------------------------------------------===//
  283. /// FoldingSetNodeIDRef - This class describes a reference to an interned
  284. /// FoldingSetNodeID, which can be a useful to store node id data rather
  285. /// than using plain FoldingSetNodeIDs, since the 32-element SmallVector
  286. /// is often much larger than necessary, and the possibility of heap
  287. /// allocation means it requires a non-trivial destructor call.
  288. class FoldingSetNodeIDRef {
  289.   const unsigned *Data = nullptr;
  290.   size_t Size = 0;
  291.  
  292. public:
  293.   FoldingSetNodeIDRef() = default;
  294.   FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {}
  295.  
  296.   /// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef,
  297.   /// used to lookup the node in the FoldingSetBase.
  298.   unsigned ComputeHash() const {
  299.     return static_cast<unsigned>(hash_combine_range(Data, Data + Size));
  300.   }
  301.  
  302.   bool operator==(FoldingSetNodeIDRef) const;
  303.  
  304.   bool operator!=(FoldingSetNodeIDRef RHS) const { return !(*this == RHS); }
  305.  
  306.   /// Used to compare the "ordering" of two nodes as defined by the
  307.   /// profiled bits and their ordering defined by memcmp().
  308.   bool operator<(FoldingSetNodeIDRef) const;
  309.  
  310.   const unsigned *getData() const { return Data; }
  311.   size_t getSize() const { return Size; }
  312. };
  313.  
  314. //===--------------------------------------------------------------------===//
  315. /// FoldingSetNodeID - This class is used to gather all the unique data bits of
  316. /// a node.  When all the bits are gathered this class is used to produce a
  317. /// hash value for the node.
  318. class FoldingSetNodeID {
  319.   /// Bits - Vector of all the data bits that make the node unique.
  320.   /// Use a SmallVector to avoid a heap allocation in the common case.
  321.   SmallVector<unsigned, 32> Bits;
  322.  
  323. public:
  324.   FoldingSetNodeID() = default;
  325.  
  326.   FoldingSetNodeID(FoldingSetNodeIDRef Ref)
  327.     : Bits(Ref.getData(), Ref.getData() + Ref.getSize()) {}
  328.  
  329.   /// Add* - Add various data types to Bit data.
  330.   void AddPointer(const void *Ptr) {
  331.     // Note: this adds pointers to the hash using sizes and endianness that
  332.     // depend on the host. It doesn't matter, however, because hashing on
  333.     // pointer values is inherently unstable. Nothing should depend on the
  334.     // ordering of nodes in the folding set.
  335.     static_assert(sizeof(uintptr_t) <= sizeof(unsigned long long),
  336.                   "unexpected pointer size");
  337.     AddInteger(reinterpret_cast<uintptr_t>(Ptr));
  338.   }
  339.   void AddInteger(signed I) { Bits.push_back(I); }
  340.   void AddInteger(unsigned I) { Bits.push_back(I); }
  341.   void AddInteger(long I) { AddInteger((unsigned long)I); }
  342.   void AddInteger(unsigned long I) {
  343.     if (sizeof(long) == sizeof(int))
  344.       AddInteger(unsigned(I));
  345.     else if (sizeof(long) == sizeof(long long)) {
  346.       AddInteger((unsigned long long)I);
  347.     } else {
  348.       llvm_unreachable("unexpected sizeof(long)");
  349.     }
  350.   }
  351.   void AddInteger(long long I) { AddInteger((unsigned long long)I); }
  352.   void AddInteger(unsigned long long I) {
  353.     AddInteger(unsigned(I));
  354.     AddInteger(unsigned(I >> 32));
  355.   }
  356.  
  357.   void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
  358.   void AddString(StringRef String);
  359.   void AddNodeID(const FoldingSetNodeID &ID);
  360.  
  361.   template <typename T>
  362.   inline void Add(const T &x) { FoldingSetTrait<T>::Profile(x, *this); }
  363.  
  364.   /// clear - Clear the accumulated profile, allowing this FoldingSetNodeID
  365.   /// object to be used to compute a new profile.
  366.   inline void clear() { Bits.clear(); }
  367.  
  368.   /// ComputeHash - Compute a strong hash value for this FoldingSetNodeID, used
  369.   /// to lookup the node in the FoldingSetBase.
  370.   unsigned ComputeHash() const {
  371.     return FoldingSetNodeIDRef(Bits.data(), Bits.size()).ComputeHash();
  372.   }
  373.  
  374.   /// operator== - Used to compare two nodes to each other.
  375.   bool operator==(const FoldingSetNodeID &RHS) const;
  376.   bool operator==(const FoldingSetNodeIDRef RHS) const;
  377.  
  378.   bool operator!=(const FoldingSetNodeID &RHS) const { return !(*this == RHS); }
  379.   bool operator!=(const FoldingSetNodeIDRef RHS) const { return !(*this ==RHS);}
  380.  
  381.   /// Used to compare the "ordering" of two nodes as defined by the
  382.   /// profiled bits and their ordering defined by memcmp().
  383.   bool operator<(const FoldingSetNodeID &RHS) const;
  384.   bool operator<(const FoldingSetNodeIDRef RHS) const;
  385.  
  386.   /// Intern - Copy this node's data to a memory region allocated from the
  387.   /// given allocator and return a FoldingSetNodeIDRef describing the
  388.   /// interned data.
  389.   FoldingSetNodeIDRef Intern(BumpPtrAllocator &Allocator) const;
  390. };
  391.  
  392. // Convenience type to hide the implementation of the folding set.
  393. using FoldingSetNode = FoldingSetBase::Node;
  394. template<class T> class FoldingSetIterator;
  395. template<class T> class FoldingSetBucketIterator;
  396.  
  397. // Definitions of FoldingSetTrait and ContextualFoldingSetTrait functions, which
  398. // require the definition of FoldingSetNodeID.
  399. template<typename T>
  400. inline bool
  401. DefaultFoldingSetTrait<T>::Equals(T &X, const FoldingSetNodeID &ID,
  402.                                   unsigned /*IDHash*/,
  403.                                   FoldingSetNodeID &TempID) {
  404.   FoldingSetTrait<T>::Profile(X, TempID);
  405.   return TempID == ID;
  406. }
  407. template<typename T>
  408. inline unsigned
  409. DefaultFoldingSetTrait<T>::ComputeHash(T &X, FoldingSetNodeID &TempID) {
  410.   FoldingSetTrait<T>::Profile(X, TempID);
  411.   return TempID.ComputeHash();
  412. }
  413. template<typename T, typename Ctx>
  414. inline bool
  415. DefaultContextualFoldingSetTrait<T, Ctx>::Equals(T &X,
  416.                                                  const FoldingSetNodeID &ID,
  417.                                                  unsigned /*IDHash*/,
  418.                                                  FoldingSetNodeID &TempID,
  419.                                                  Ctx Context) {
  420.   ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context);
  421.   return TempID == ID;
  422. }
  423. template<typename T, typename Ctx>
  424. inline unsigned
  425. DefaultContextualFoldingSetTrait<T, Ctx>::ComputeHash(T &X,
  426.                                                       FoldingSetNodeID &TempID,
  427.                                                       Ctx Context) {
  428.   ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context);
  429.   return TempID.ComputeHash();
  430. }
  431.  
  432. //===----------------------------------------------------------------------===//
  433. /// FoldingSetImpl - An implementation detail that lets us share code between
  434. /// FoldingSet and ContextualFoldingSet.
  435. template <class Derived, class T> class FoldingSetImpl : public FoldingSetBase {
  436. protected:
  437.   explicit FoldingSetImpl(unsigned Log2InitSize)
  438.       : FoldingSetBase(Log2InitSize) {}
  439.  
  440.   FoldingSetImpl(FoldingSetImpl &&Arg) = default;
  441.   FoldingSetImpl &operator=(FoldingSetImpl &&RHS) = default;
  442.   ~FoldingSetImpl() = default;
  443.  
  444. public:
  445.   using iterator = FoldingSetIterator<T>;
  446.  
  447.   iterator begin() { return iterator(Buckets); }
  448.   iterator end() { return iterator(Buckets+NumBuckets); }
  449.  
  450.   using const_iterator = FoldingSetIterator<const T>;
  451.  
  452.   const_iterator begin() const { return const_iterator(Buckets); }
  453.   const_iterator end() const { return const_iterator(Buckets+NumBuckets); }
  454.  
  455.   using bucket_iterator = FoldingSetBucketIterator<T>;
  456.  
  457.   bucket_iterator bucket_begin(unsigned hash) {
  458.     return bucket_iterator(Buckets + (hash & (NumBuckets-1)));
  459.   }
  460.  
  461.   bucket_iterator bucket_end(unsigned hash) {
  462.     return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true);
  463.   }
  464.  
  465.   /// reserve - Increase the number of buckets such that adding the
  466.   /// EltCount-th node won't cause a rebucket operation. reserve is permitted
  467.   /// to allocate more space than requested by EltCount.
  468.   void reserve(unsigned EltCount) {
  469.     return FoldingSetBase::reserve(EltCount, Derived::getFoldingSetInfo());
  470.   }
  471.  
  472.   /// RemoveNode - Remove a node from the folding set, returning true if one
  473.   /// was removed or false if the node was not in the folding set.
  474.   bool RemoveNode(T *N) {
  475.     return FoldingSetBase::RemoveNode(N);
  476.   }
  477.  
  478.   /// GetOrInsertNode - If there is an existing simple Node exactly
  479.   /// equal to the specified node, return it.  Otherwise, insert 'N' and
  480.   /// return it instead.
  481.   T *GetOrInsertNode(T *N) {
  482.     return static_cast<T *>(
  483.         FoldingSetBase::GetOrInsertNode(N, Derived::getFoldingSetInfo()));
  484.   }
  485.  
  486.   /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
  487.   /// return it.  If not, return the insertion token that will make insertion
  488.   /// faster.
  489.   T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
  490.     return static_cast<T *>(FoldingSetBase::FindNodeOrInsertPos(
  491.         ID, InsertPos, Derived::getFoldingSetInfo()));
  492.   }
  493.  
  494.   /// InsertNode - Insert the specified node into the folding set, knowing that
  495.   /// it is not already in the folding set.  InsertPos must be obtained from
  496.   /// FindNodeOrInsertPos.
  497.   void InsertNode(T *N, void *InsertPos) {
  498.     FoldingSetBase::InsertNode(N, InsertPos, Derived::getFoldingSetInfo());
  499.   }
  500.  
  501.   /// InsertNode - Insert the specified node into the folding set, knowing that
  502.   /// it is not already in the folding set.
  503.   void InsertNode(T *N) {
  504.     T *Inserted = GetOrInsertNode(N);
  505.     (void)Inserted;
  506.     assert(Inserted == N && "Node already inserted!");
  507.   }
  508. };
  509.  
  510. //===----------------------------------------------------------------------===//
  511. /// FoldingSet - This template class is used to instantiate a specialized
  512. /// implementation of the folding set to the node class T.  T must be a
  513. /// subclass of FoldingSetNode and implement a Profile function.
  514. ///
  515. /// Note that this set type is movable and move-assignable. However, its
  516. /// moved-from state is not a valid state for anything other than
  517. /// move-assigning and destroying. This is primarily to enable movable APIs
  518. /// that incorporate these objects.
  519. template <class T>
  520. class FoldingSet : public FoldingSetImpl<FoldingSet<T>, T> {
  521.   using Super = FoldingSetImpl<FoldingSet, T>;
  522.   using Node = typename Super::Node;
  523.  
  524.   /// GetNodeProfile - Each instantiation of the FoldingSet needs to provide a
  525.   /// way to convert nodes into a unique specifier.
  526.   static void GetNodeProfile(const FoldingSetBase *, Node *N,
  527.                              FoldingSetNodeID &ID) {
  528.     T *TN = static_cast<T *>(N);
  529.     FoldingSetTrait<T>::Profile(*TN, ID);
  530.   }
  531.  
  532.   /// NodeEquals - Instantiations may optionally provide a way to compare a
  533.   /// node with a specified ID.
  534.   static bool NodeEquals(const FoldingSetBase *, Node *N,
  535.                          const FoldingSetNodeID &ID, unsigned IDHash,
  536.                          FoldingSetNodeID &TempID) {
  537.     T *TN = static_cast<T *>(N);
  538.     return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID);
  539.   }
  540.  
  541.   /// ComputeNodeHash - Instantiations may optionally provide a way to compute a
  542.   /// hash value directly from a node.
  543.   static unsigned ComputeNodeHash(const FoldingSetBase *, Node *N,
  544.                                   FoldingSetNodeID &TempID) {
  545.     T *TN = static_cast<T *>(N);
  546.     return FoldingSetTrait<T>::ComputeHash(*TN, TempID);
  547.   }
  548.  
  549.   static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo() {
  550.     static constexpr FoldingSetBase::FoldingSetInfo Info = {
  551.         GetNodeProfile, NodeEquals, ComputeNodeHash};
  552.     return Info;
  553.   }
  554.   friend Super;
  555.  
  556. public:
  557.   explicit FoldingSet(unsigned Log2InitSize = 6) : Super(Log2InitSize) {}
  558.   FoldingSet(FoldingSet &&Arg) = default;
  559.   FoldingSet &operator=(FoldingSet &&RHS) = default;
  560. };
  561.  
  562. //===----------------------------------------------------------------------===//
  563. /// ContextualFoldingSet - This template class is a further refinement
  564. /// of FoldingSet which provides a context argument when calling
  565. /// Profile on its nodes.  Currently, that argument is fixed at
  566. /// initialization time.
  567. ///
  568. /// T must be a subclass of FoldingSetNode and implement a Profile
  569. /// function with signature
  570. ///   void Profile(FoldingSetNodeID &, Ctx);
  571. template <class T, class Ctx>
  572. class ContextualFoldingSet
  573.     : public FoldingSetImpl<ContextualFoldingSet<T, Ctx>, T> {
  574.   // Unfortunately, this can't derive from FoldingSet<T> because the
  575.   // construction of the vtable for FoldingSet<T> requires
  576.   // FoldingSet<T>::GetNodeProfile to be instantiated, which in turn
  577.   // requires a single-argument T::Profile().
  578.  
  579.   using Super = FoldingSetImpl<ContextualFoldingSet, T>;
  580.   using Node = typename Super::Node;
  581.  
  582.   Ctx Context;
  583.  
  584.   static const Ctx &getContext(const FoldingSetBase *Base) {
  585.     return static_cast<const ContextualFoldingSet*>(Base)->Context;
  586.   }
  587.  
  588.   /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
  589.   /// way to convert nodes into a unique specifier.
  590.   static void GetNodeProfile(const FoldingSetBase *Base, Node *N,
  591.                              FoldingSetNodeID &ID) {
  592.     T *TN = static_cast<T *>(N);
  593.     ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, getContext(Base));
  594.   }
  595.  
  596.   static bool NodeEquals(const FoldingSetBase *Base, Node *N,
  597.                          const FoldingSetNodeID &ID, unsigned IDHash,
  598.                          FoldingSetNodeID &TempID) {
  599.     T *TN = static_cast<T *>(N);
  600.     return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID,
  601.                                                      getContext(Base));
  602.   }
  603.  
  604.   static unsigned ComputeNodeHash(const FoldingSetBase *Base, Node *N,
  605.                                   FoldingSetNodeID &TempID) {
  606.     T *TN = static_cast<T *>(N);
  607.     return ContextualFoldingSetTrait<T, Ctx>::ComputeHash(*TN, TempID,
  608.                                                           getContext(Base));
  609.   }
  610.  
  611.   static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo() {
  612.     static constexpr FoldingSetBase::FoldingSetInfo Info = {
  613.         GetNodeProfile, NodeEquals, ComputeNodeHash};
  614.     return Info;
  615.   }
  616.   friend Super;
  617.  
  618. public:
  619.   explicit ContextualFoldingSet(Ctx Context, unsigned Log2InitSize = 6)
  620.       : Super(Log2InitSize), Context(Context) {}
  621.  
  622.   Ctx getContext() const { return Context; }
  623. };
  624.  
  625. //===----------------------------------------------------------------------===//
  626. /// FoldingSetVector - This template class combines a FoldingSet and a vector
  627. /// to provide the interface of FoldingSet but with deterministic iteration
  628. /// order based on the insertion order. T must be a subclass of FoldingSetNode
  629. /// and implement a Profile function.
  630. template <class T, class VectorT = SmallVector<T*, 8>>
  631. class FoldingSetVector {
  632.   FoldingSet<T> Set;
  633.   VectorT Vector;
  634.  
  635. public:
  636.   explicit FoldingSetVector(unsigned Log2InitSize = 6) : Set(Log2InitSize) {}
  637.  
  638.   using iterator = pointee_iterator<typename VectorT::iterator>;
  639.  
  640.   iterator begin() { return Vector.begin(); }
  641.   iterator end()   { return Vector.end(); }
  642.  
  643.   using const_iterator = pointee_iterator<typename VectorT::const_iterator>;
  644.  
  645.   const_iterator begin() const { return Vector.begin(); }
  646.   const_iterator end()   const { return Vector.end(); }
  647.  
  648.   /// clear - Remove all nodes from the folding set.
  649.   void clear() { Set.clear(); Vector.clear(); }
  650.  
  651.   /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
  652.   /// return it.  If not, return the insertion token that will make insertion
  653.   /// faster.
  654.   T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
  655.     return Set.FindNodeOrInsertPos(ID, InsertPos);
  656.   }
  657.  
  658.   /// GetOrInsertNode - If there is an existing simple Node exactly
  659.   /// equal to the specified node, return it.  Otherwise, insert 'N' and
  660.   /// return it instead.
  661.   T *GetOrInsertNode(T *N) {
  662.     T *Result = Set.GetOrInsertNode(N);
  663.     if (Result == N) Vector.push_back(N);
  664.     return Result;
  665.   }
  666.  
  667.   /// InsertNode - Insert the specified node into the folding set, knowing that
  668.   /// it is not already in the folding set.  InsertPos must be obtained from
  669.   /// FindNodeOrInsertPos.
  670.   void InsertNode(T *N, void *InsertPos) {
  671.     Set.InsertNode(N, InsertPos);
  672.     Vector.push_back(N);
  673.   }
  674.  
  675.   /// InsertNode - Insert the specified node into the folding set, knowing that
  676.   /// it is not already in the folding set.
  677.   void InsertNode(T *N) {
  678.     Set.InsertNode(N);
  679.     Vector.push_back(N);
  680.   }
  681.  
  682.   /// size - Returns the number of nodes in the folding set.
  683.   unsigned size() const { return Set.size(); }
  684.  
  685.   /// empty - Returns true if there are no nodes in the folding set.
  686.   bool empty() const { return Set.empty(); }
  687. };
  688.  
  689. //===----------------------------------------------------------------------===//
  690. /// FoldingSetIteratorImpl - This is the common iterator support shared by all
  691. /// folding sets, which knows how to walk the folding set hash table.
  692. class FoldingSetIteratorImpl {
  693. protected:
  694.   FoldingSetNode *NodePtr;
  695.  
  696.   FoldingSetIteratorImpl(void **Bucket);
  697.  
  698.   void advance();
  699.  
  700. public:
  701.   bool operator==(const FoldingSetIteratorImpl &RHS) const {
  702.     return NodePtr == RHS.NodePtr;
  703.   }
  704.   bool operator!=(const FoldingSetIteratorImpl &RHS) const {
  705.     return NodePtr != RHS.NodePtr;
  706.   }
  707. };
  708.  
  709. template <class T> class FoldingSetIterator : public FoldingSetIteratorImpl {
  710. public:
  711.   explicit FoldingSetIterator(void **Bucket) : FoldingSetIteratorImpl(Bucket) {}
  712.  
  713.   T &operator*() const {
  714.     return *static_cast<T*>(NodePtr);
  715.   }
  716.  
  717.   T *operator->() const {
  718.     return static_cast<T*>(NodePtr);
  719.   }
  720.  
  721.   inline FoldingSetIterator &operator++() {          // Preincrement
  722.     advance();
  723.     return *this;
  724.   }
  725.   FoldingSetIterator operator++(int) {        // Postincrement
  726.     FoldingSetIterator tmp = *this; ++*this; return tmp;
  727.   }
  728. };
  729.  
  730. //===----------------------------------------------------------------------===//
  731. /// FoldingSetBucketIteratorImpl - This is the common bucket iterator support
  732. /// shared by all folding sets, which knows how to walk a particular bucket
  733. /// of a folding set hash table.
  734. class FoldingSetBucketIteratorImpl {
  735. protected:
  736.   void *Ptr;
  737.  
  738.   explicit FoldingSetBucketIteratorImpl(void **Bucket);
  739.  
  740.   FoldingSetBucketIteratorImpl(void **Bucket, bool) : Ptr(Bucket) {}
  741.  
  742.   void advance() {
  743.     void *Probe = static_cast<FoldingSetNode*>(Ptr)->getNextInBucket();
  744.     uintptr_t x = reinterpret_cast<uintptr_t>(Probe) & ~0x1;
  745.     Ptr = reinterpret_cast<void*>(x);
  746.   }
  747.  
  748. public:
  749.   bool operator==(const FoldingSetBucketIteratorImpl &RHS) const {
  750.     return Ptr == RHS.Ptr;
  751.   }
  752.   bool operator!=(const FoldingSetBucketIteratorImpl &RHS) const {
  753.     return Ptr != RHS.Ptr;
  754.   }
  755. };
  756.  
  757. template <class T>
  758. class FoldingSetBucketIterator : public FoldingSetBucketIteratorImpl {
  759. public:
  760.   explicit FoldingSetBucketIterator(void **Bucket) :
  761.     FoldingSetBucketIteratorImpl(Bucket) {}
  762.  
  763.   FoldingSetBucketIterator(void **Bucket, bool) :
  764.     FoldingSetBucketIteratorImpl(Bucket, true) {}
  765.  
  766.   T &operator*() const { return *static_cast<T*>(Ptr); }
  767.   T *operator->() const { return static_cast<T*>(Ptr); }
  768.  
  769.   inline FoldingSetBucketIterator &operator++() { // Preincrement
  770.     advance();
  771.     return *this;
  772.   }
  773.   FoldingSetBucketIterator operator++(int) {      // Postincrement
  774.     FoldingSetBucketIterator tmp = *this; ++*this; return tmp;
  775.   }
  776. };
  777.  
  778. //===----------------------------------------------------------------------===//
  779. /// FoldingSetNodeWrapper - This template class is used to "wrap" arbitrary
  780. /// types in an enclosing object so that they can be inserted into FoldingSets.
  781. template <typename T>
  782. class FoldingSetNodeWrapper : public FoldingSetNode {
  783.   T data;
  784.  
  785. public:
  786.   template <typename... Ts>
  787.   explicit FoldingSetNodeWrapper(Ts &&... Args)
  788.       : data(std::forward<Ts>(Args)...) {}
  789.  
  790.   void Profile(FoldingSetNodeID &ID) { FoldingSetTrait<T>::Profile(data, ID); }
  791.  
  792.   T &getValue() { return data; }
  793.   const T &getValue() const { return data; }
  794.  
  795.   operator T&() { return data; }
  796.   operator const T&() const { return data; }
  797. };
  798.  
  799. //===----------------------------------------------------------------------===//
  800. /// FastFoldingSetNode - This is a subclass of FoldingSetNode which stores
  801. /// a FoldingSetNodeID value rather than requiring the node to recompute it
  802. /// each time it is needed. This trades space for speed (which can be
  803. /// significant if the ID is long), and it also permits nodes to drop
  804. /// information that would otherwise only be required for recomputing an ID.
  805. class FastFoldingSetNode : public FoldingSetNode {
  806.   FoldingSetNodeID FastID;
  807.  
  808. protected:
  809.   explicit FastFoldingSetNode(const FoldingSetNodeID &ID) : FastID(ID) {}
  810.  
  811. public:
  812.   void Profile(FoldingSetNodeID &ID) const { ID.AddNodeID(FastID); }
  813. };
  814.  
  815. //===----------------------------------------------------------------------===//
  816. // Partial specializations of FoldingSetTrait.
  817.  
  818. template<typename T> struct FoldingSetTrait<T*> {
  819.   static inline void Profile(T *X, FoldingSetNodeID &ID) {
  820.     ID.AddPointer(X);
  821.   }
  822. };
  823. template <typename T1, typename T2>
  824. struct FoldingSetTrait<std::pair<T1, T2>> {
  825.   static inline void Profile(const std::pair<T1, T2> &P,
  826.                              FoldingSetNodeID &ID) {
  827.     ID.Add(P.first);
  828.     ID.Add(P.second);
  829.   }
  830. };
  831.  
  832. template <typename T>
  833. struct FoldingSetTrait<T, std::enable_if_t<std::is_enum<T>::value>> {
  834.   static void Profile(const T &X, FoldingSetNodeID &ID) {
  835.     ID.AddInteger(static_cast<std::underlying_type_t<T>>(X));
  836.   }
  837. };
  838.  
  839. } // end namespace llvm
  840.  
  841. #endif // LLVM_ADT_FOLDINGSET_H
  842.