LLVM API Documentation

FoldingSet.h

Go to the documentation of this file.
00001 //===-- llvm/ADT/FoldingSet.h - Uniquing Hash Set ---------------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file defines a hash set that can be used to remove duplication of nodes
00011 // in a graph.  This code was originally created by Chris Lattner for use with
00012 // SelectionDAGCSEMap, but was isolated to provide use across the llvm code set.
00013 //
00014 //===----------------------------------------------------------------------===//
00015 
00016 #ifndef LLVM_ADT_FOLDINGSET_H
00017 #define LLVM_ADT_FOLDINGSET_H
00018 
00019 #include "llvm/Support/DataTypes.h"
00020 #include "llvm/ADT/SmallVector.h"
00021 #include <string>
00022 
00023 namespace llvm {
00024   class APFloat;
00025   class APInt;
00026 
00027 /// This folding set used for two purposes:
00028 ///   1. Given information about a node we want to create, look up the unique
00029 ///      instance of the node in the set.  If the node already exists, return
00030 ///      it, otherwise return the bucket it should be inserted into.
00031 ///   2. Given a node that has already been created, remove it from the set.
00032 ///
00033 /// This class is implemented as a single-link chained hash table, where the
00034 /// "buckets" are actually the nodes themselves (the next pointer is in the
00035 /// node).  The last node points back to the bucket to simplify node removal.
00036 ///
00037 /// Any node that is to be included in the folding set must be a subclass of
00038 /// FoldingSetNode.  The node class must also define a Profile method used to
00039 /// establish the unique bits of data for the node.  The Profile method is
00040 /// passed a FoldingSetNodeID object which is used to gather the bits.  Just
00041 /// call one of the Add* functions defined in the FoldingSetImpl::NodeID class.
00042 /// NOTE: That the folding set does not own the nodes and it is the
00043 /// responsibility of the user to dispose of the nodes.
00044 ///
00045 /// Eg.
00046 ///    class MyNode : public FoldingSetNode {
00047 ///    private:
00048 ///      std::string Name;
00049 ///      unsigned Value;
00050 ///    public:
00051 ///      MyNode(const char *N, unsigned V) : Name(N), Value(V) {}
00052 ///       ...
00053 ///      void Profile(FoldingSetNodeID &ID) {
00054 ///        ID.AddString(Name);
00055 ///        ID.AddInteger(Value);
00056 ///       }
00057 ///       ...
00058 ///     };
00059 ///
00060 /// To define the folding set itself use the FoldingSet template;
00061 ///
00062 /// Eg.
00063 ///    FoldingSet<MyNode> MyFoldingSet;
00064 ///
00065 /// Four public methods are available to manipulate the folding set;
00066 ///
00067 /// 1) If you have an existing node that you want add to the set but unsure
00068 /// that the node might already exist then call;
00069 ///
00070 ///    MyNode *M = MyFoldingSet.GetOrInsertNode(N);
00071 ///
00072 /// If The result is equal to the input then the node has been inserted.
00073 /// Otherwise, the result is the node existing in the folding set, and the
00074 /// input can be discarded (use the result instead.)
00075 ///
00076 /// 2) If you are ready to construct a node but want to check if it already
00077 /// exists, then call FindNodeOrInsertPos with a FoldingSetNodeID of the bits to
00078 /// check;
00079 ///
00080 ///   FoldingSetNodeID ID;
00081 ///   ID.AddString(Name);
00082 ///   ID.AddInteger(Value);
00083 ///   void *InsertPoint;
00084 ///
00085 ///    MyNode *M = MyFoldingSet.FindNodeOrInsertPos(ID, InsertPoint);
00086 ///
00087 /// If found then M with be non-NULL, else InsertPoint will point to where it
00088 /// should be inserted using InsertNode.
00089 ///
00090 /// 3) If you get a NULL result from FindNodeOrInsertPos then you can as a new
00091 /// node with FindNodeOrInsertPos;
00092 ///
00093 ///    InsertNode(N, InsertPoint);
00094 ///
00095 /// 4) Finally, if you want to remove a node from the folding set call;
00096 ///
00097 ///    bool WasRemoved = RemoveNode(N);
00098 ///
00099 /// The result indicates whether the node existed in the folding set.
00100 
00101 class FoldingSetNodeID;
00102 
00103 //===----------------------------------------------------------------------===//
00104 /// FoldingSetImpl - Implements the folding set functionality.  The main
00105 /// structure is an array of buckets.  Each bucket is indexed by the hash of
00106 /// the nodes it contains.  The bucket itself points to the nodes contained
00107 /// in the bucket via a singly linked list.  The last node in the list points
00108 /// back to the bucket to facilitate node removal.
00109 ///
00110 class FoldingSetImpl {
00111 protected:
00112   /// Buckets - Array of bucket chains.
00113   ///
00114   void **Buckets;
00115 
00116   /// NumBuckets - Length of the Buckets array.  Always a power of 2.
00117   ///
00118   unsigned NumBuckets;
00119 
00120   /// NumNodes - Number of nodes in the folding set. Growth occurs when NumNodes
00121   /// is greater than twice the number of buckets.
00122   unsigned NumNodes;
00123 
00124 public:
00125   explicit FoldingSetImpl(unsigned Log2InitSize = 6);
00126   virtual ~FoldingSetImpl();
00127 
00128   //===--------------------------------------------------------------------===//
00129   /// Node - This class is used to maintain the singly linked bucket list in
00130   /// a folding set.
00131   ///
00132   class Node {
00133   private:
00134     // NextInFoldingSetBucket - next link in the bucket list.
00135     void *NextInFoldingSetBucket;
00136 
00137   public:
00138 
00139     Node() : NextInFoldingSetBucket(0) {}
00140 
00141     // Accessors
00142     void *getNextInBucket() const { return NextInFoldingSetBucket; }
00143     void SetNextInBucket(void *N) { NextInFoldingSetBucket = N; }
00144   };
00145 
00146   /// clear - Remove all nodes from the folding set.
00147   void clear();
00148 
00149   /// RemoveNode - Remove a node from the folding set, returning true if one
00150   /// was removed or false if the node was not in the folding set.
00151   bool RemoveNode(Node *N);
00152 
00153   /// GetOrInsertNode - If there is an existing simple Node exactly
00154   /// equal to the specified node, return it.  Otherwise, insert 'N' and return
00155   /// it instead.
00156   Node *GetOrInsertNode(Node *N);
00157 
00158   /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
00159   /// return it.  If not, return the insertion token that will make insertion
00160   /// faster.
00161   Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos);
00162 
00163   /// InsertNode - Insert the specified node into the folding set, knowing that
00164   /// it is not already in the folding set.  InsertPos must be obtained from
00165   /// FindNodeOrInsertPos.
00166   void InsertNode(Node *N, void *InsertPos);
00167 
00168   /// size - Returns the number of nodes in the folding set.
00169   unsigned size() const { return NumNodes; }
00170 
00171   /// empty - Returns true if there are no nodes in the folding set.
00172   bool empty() const { return NumNodes == 0; }
00173 
00174 private:
00175 
00176   /// GrowHashTable - Double the size of the hash table and rehash everything.
00177   ///
00178   void GrowHashTable();
00179 
00180 protected:
00181 
00182   /// GetNodeProfile - Instantiations of the FoldingSet template implement
00183   /// this function to gather data bits for the given node.
00184   virtual void GetNodeProfile(FoldingSetNodeID &ID, Node *N) const = 0;
00185 };
00186 
00187 //===----------------------------------------------------------------------===//
00188 /// FoldingSetTrait - This trait class is used to define behavior of how
00189 ///  to "profile" (in the FoldingSet parlance) an object of a given type.
00190 ///  The default behavior is to invoke a 'Profile' method on an object, but
00191 ///  through template specialization the behavior can be tailored for specific
00192 ///  types.  Combined with the FoldingSetNodeWrapper classs, one can add objects
00193 ///  to FoldingSets that were not originally designed to have that behavior.
00194 ///
00195 template<typename T> struct FoldingSetTrait {
00196   static inline void Profile(const T& X, FoldingSetNodeID& ID) { X.Profile(ID);}
00197   static inline void Profile(T& X, FoldingSetNodeID& ID) { X.Profile(ID); }
00198 };
00199 
00200 //===--------------------------------------------------------------------===//
00201 /// FoldingSetNodeID - This class is used to gather all the unique data bits of
00202 /// a node.  When all the bits are gathered this class is used to produce a
00203 /// hash value for the node.
00204 ///
00205 class FoldingSetNodeID {
00206   /// Bits - Vector of all the data bits that make the node unique.
00207   /// Use a SmallVector to avoid a heap allocation in the common case.
00208   SmallVector<unsigned, 32> Bits;
00209 
00210 public:
00211   FoldingSetNodeID() {}
00212 
00213   /// getRawData - Return the ith entry in the Bits data.
00214   ///
00215   unsigned getRawData(unsigned i) const {
00216     return Bits[i];
00217   }
00218 
00219   /// Add* - Add various data types to Bit data.
00220   ///
00221   void AddPointer(const void *Ptr);
00222   void AddInteger(signed I);
00223   void AddInteger(unsigned I);
00224   void AddInteger(long I);
00225   void AddInteger(unsigned long I);
00226   void AddInteger(long long I);
00227   void AddInteger(unsigned long long I);
00228   void AddString(const std::string &String);
00229   void AddString(const char* String);
00230 
00231   template <typename T>
00232   inline void Add(const T& x) { FoldingSetTrait<T>::Profile(x, *this); }
00233 
00234   /// clear - Clear the accumulated profile, allowing this FoldingSetNodeID
00235   ///  object to be used to compute a new profile.
00236   inline void clear() { Bits.clear(); }
00237 
00238   /// ComputeHash - Compute a strong hash value for this FoldingSetNodeID, used
00239   ///  to lookup the node in the FoldingSetImpl.
00240   unsigned ComputeHash() const;
00241 
00242   /// operator== - Used to compare two nodes to each other.
00243   ///
00244   bool operator==(const FoldingSetNodeID &RHS) const;
00245 };
00246 
00247 // Convenience type to hide the implementation of the folding set.
00248 typedef FoldingSetImpl::Node FoldingSetNode;
00249 template<class T> class FoldingSetIterator;
00250 template<class T> class FoldingSetBucketIterator;
00251 
00252 //===----------------------------------------------------------------------===//
00253 /// FoldingSet - This template class is used to instantiate a specialized
00254 /// implementation of the folding set to the node class T.  T must be a
00255 /// subclass of FoldingSetNode and implement a Profile function.
00256 ///
00257 template<class T> class FoldingSet : public FoldingSetImpl {
00258 private:
00259   /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
00260   /// way to convert nodes into a unique specifier.
00261   virtual void GetNodeProfile(FoldingSetNodeID &ID, Node *N) const {
00262     T *TN = static_cast<T *>(N);
00263     FoldingSetTrait<T>::Profile(*TN,ID);
00264   }
00265 
00266 public:
00267   explicit FoldingSet(unsigned Log2InitSize = 6)
00268   : FoldingSetImpl(Log2InitSize)
00269   {}
00270 
00271   typedef FoldingSetIterator<T> iterator;
00272   iterator begin() { return iterator(Buckets); }
00273   iterator end() { return iterator(Buckets+NumBuckets); }
00274 
00275   typedef FoldingSetIterator<const T> const_iterator;
00276   const_iterator begin() const { return const_iterator(Buckets); }
00277   const_iterator end() const { return const_iterator(Buckets+NumBuckets); }
00278 
00279   typedef FoldingSetBucketIterator<T> bucket_iterator;
00280 
00281   bucket_iterator bucket_begin(unsigned hash) {
00282     return bucket_iterator(Buckets + (hash & (NumBuckets-1)));
00283   }
00284 
00285   bucket_iterator bucket_end(unsigned hash) {
00286     return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true);
00287   }
00288 
00289   /// GetOrInsertNode - If there is an existing simple Node exactly
00290   /// equal to the specified node, return it.  Otherwise, insert 'N' and
00291   /// return it instead.
00292   T *GetOrInsertNode(Node *N) {
00293     return static_cast<T *>(FoldingSetImpl::GetOrInsertNode(N));
00294   }
00295 
00296   /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
00297   /// return it.  If not, return the insertion token that will make insertion
00298   /// faster.
00299   T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
00300     return static_cast<T *>(FoldingSetImpl::FindNodeOrInsertPos(ID, InsertPos));
00301   }
00302 };
00303 
00304 //===----------------------------------------------------------------------===//
00305 /// FoldingSetIteratorImpl - This is the common iterator support shared by all
00306 /// folding sets, which knows how to walk the folding set hash table.
00307 class FoldingSetIteratorImpl {
00308 protected:
00309   FoldingSetNode *NodePtr;
00310   FoldingSetIteratorImpl(void **Bucket);
00311   void advance();
00312 
00313 public:
00314   bool operator==(const FoldingSetIteratorImpl &RHS) const {
00315     return NodePtr == RHS.NodePtr;
00316   }
00317   bool operator!=(const FoldingSetIteratorImpl &RHS) const {
00318     return NodePtr != RHS.NodePtr;
00319   }
00320 };
00321 
00322 
00323 template<class T>
00324 class FoldingSetIterator : public FoldingSetIteratorImpl {
00325 public:
00326   explicit FoldingSetIterator(void **Bucket) : FoldingSetIteratorImpl(Bucket) {}
00327 
00328   T &operator*() const {
00329     return *static_cast<T*>(NodePtr);
00330   }
00331 
00332   T *operator->() const {
00333     return static_cast<T*>(NodePtr);
00334   }
00335 
00336   inline FoldingSetIterator& operator++() {          // Preincrement
00337     advance();
00338     return *this;
00339   }
00340   FoldingSetIterator operator++(int) {        // Postincrement
00341     FoldingSetIterator tmp = *this; ++*this; return tmp;
00342   }
00343 };
00344 
00345 //===----------------------------------------------------------------------===//
00346 /// FoldingSetBucketIteratorImpl - This is the common bucket iterator support
00347 ///  shared by all folding sets, which knows how to walk a particular bucket
00348 ///  of a folding set hash table.
00349 
00350 class FoldingSetBucketIteratorImpl {
00351 protected:
00352   void *Ptr;
00353 
00354   explicit FoldingSetBucketIteratorImpl(void **Bucket);
00355 
00356   FoldingSetBucketIteratorImpl(void **Bucket, bool)
00357     : Ptr(Bucket) {}
00358 
00359   void advance() {
00360     void *Probe = static_cast<FoldingSetNode*>(Ptr)->getNextInBucket();
00361     uintptr_t x = reinterpret_cast<uintptr_t>(Probe) & ~0x1;
00362     Ptr = reinterpret_cast<void*>(x);
00363   }
00364 
00365 public:
00366   bool operator==(const FoldingSetBucketIteratorImpl &RHS) const {
00367     return Ptr == RHS.Ptr;
00368   }
00369   bool operator!=(const FoldingSetBucketIteratorImpl &RHS) const {
00370     return Ptr != RHS.Ptr;
00371   }
00372 };
00373 
00374 
00375 template<class T>
00376 class FoldingSetBucketIterator : public FoldingSetBucketIteratorImpl {
00377 public:
00378   explicit FoldingSetBucketIterator(void **Bucket) :
00379     FoldingSetBucketIteratorImpl(Bucket) {}
00380 
00381   FoldingSetBucketIterator(void **Bucket, bool) :
00382     FoldingSetBucketIteratorImpl(Bucket, true) {}
00383 
00384   T& operator*() const { return *static_cast<T*>(Ptr); }
00385   T* operator->() const { return static_cast<T*>(Ptr); }
00386 
00387   inline FoldingSetBucketIterator& operator++() { // Preincrement
00388     advance();
00389     return *this;
00390   }
00391   FoldingSetBucketIterator operator++(int) {      // Postincrement
00392     FoldingSetBucketIterator tmp = *this; ++*this; return tmp;
00393   }
00394 };
00395 
00396 //===----------------------------------------------------------------------===//
00397 /// FoldingSetNodeWrapper - This template class is used to "wrap" arbitrary
00398 /// types in an enclosing object so that they can be inserted into FoldingSets.
00399 template <typename T>
00400 class FoldingSetNodeWrapper : public FoldingSetNode {
00401   T data;
00402 public:
00403   explicit FoldingSetNodeWrapper(const T& x) : data(x) {}
00404   virtual ~FoldingSetNodeWrapper() {}
00405 
00406   template<typename A1>
00407   explicit FoldingSetNodeWrapper(const A1& a1)
00408     : data(a1) {}
00409 
00410   template <typename A1, typename A2>
00411   explicit FoldingSetNodeWrapper(const A1& a1, const A2& a2)
00412     : data(a1,a2) {}
00413 
00414   template <typename A1, typename A2, typename A3>
00415   explicit FoldingSetNodeWrapper(const A1& a1, const A2& a2, const A3& a3)
00416     : data(a1,a2,a3) {}
00417 
00418   template <typename A1, typename A2, typename A3, typename A4>
00419   explicit FoldingSetNodeWrapper(const A1& a1, const A2& a2, const A3& a3,
00420                                  const A4& a4)
00421     : data(a1,a2,a3,a4) {}
00422 
00423   template <typename A1, typename A2, typename A3, typename A4, typename A5>
00424   explicit FoldingSetNodeWrapper(const A1& a1, const A2& a2, const A3& a3,
00425                                  const A4& a4, const A5& a5)
00426   : data(a1,a2,a3,a4,a5) {}
00427 
00428 
00429   void Profile(FoldingSetNodeID& ID) { FoldingSetTrait<T>::Profile(data, ID); }
00430 
00431   T& getValue() { return data; }
00432   const T& getValue() const { return data; }
00433 
00434   operator T&() { return data; }
00435   operator const T&() const { return data; }
00436 };
00437 
00438 //===----------------------------------------------------------------------===//
00439 // Partial specializations of FoldingSetTrait.
00440 
00441 template<typename T> struct FoldingSetTrait<T*> {
00442   static inline void Profile(const T* X, FoldingSetNodeID& ID) {
00443     ID.AddPointer(X);
00444   }
00445   static inline void Profile(T* X, FoldingSetNodeID& ID) {
00446     ID.AddPointer(X);
00447   }
00448 };
00449 
00450 template<typename T> struct FoldingSetTrait<const T*> {
00451   static inline void Profile(const T* X, FoldingSetNodeID& ID) {
00452     ID.AddPointer(X);
00453   }
00454 };
00455 
00456 } // End of namespace llvm.
00457 
00458 #endif