FoldingSet.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. //===-- llvm/ADT/FoldingSet.h - Uniquing Hash Set ---------------*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  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 set.
  13. //
  14. //===----------------------------------------------------------------------===//
  15. #ifndef LLVM_ADT_FOLDINGSET_H
  16. #define LLVM_ADT_FOLDINGSET_H
  17. #include "llvm/ADT/SmallVector.h"
  18. #include "llvm/ADT/StringRef.h"
  19. #include "llvm/ADT/iterator.h"
  20. #include "llvm/Support/Allocator.h"
  21. #include "llvm/Support/DataTypes.h"
  22. namespace llvm {
  23. /// This folding set used for two purposes:
  24. /// 1. Given information about a node we want to create, look up the unique
  25. /// instance of the node in the set. If the node already exists, return
  26. /// it, otherwise return the bucket it should be inserted into.
  27. /// 2. Given a node that has already been created, remove it from the set.
  28. ///
  29. /// This class is implemented as a single-link chained hash table, where the
  30. /// "buckets" are actually the nodes themselves (the next pointer is in the
  31. /// node). The last node points back to the bucket to simplify node removal.
  32. ///
  33. /// Any node that is to be included in the folding set must be a subclass of
  34. /// FoldingSetNode. The node class must also define a Profile method used to
  35. /// establish the unique bits of data for the node. The Profile method is
  36. /// passed a FoldingSetNodeID object which is used to gather the bits. Just
  37. /// call one of the Add* functions defined in the FoldingSetImpl::NodeID class.
  38. /// NOTE: That the folding set does not own the nodes and it is the
  39. /// responsibility of the user to dispose of the nodes.
  40. ///
  41. /// Eg.
  42. /// class MyNode : public FoldingSetNode {
  43. /// private:
  44. /// std::string Name;
  45. /// unsigned Value;
  46. /// public:
  47. /// MyNode(const char *N, unsigned V) : Name(N), Value(V) {}
  48. /// ...
  49. /// void Profile(FoldingSetNodeID &ID) const {
  50. /// ID.AddString(Name);
  51. /// ID.AddInteger(Value);
  52. /// }
  53. /// ...
  54. /// };
  55. ///
  56. /// To define the folding set itself use the FoldingSet template;
  57. ///
  58. /// Eg.
  59. /// FoldingSet<MyNode> MyFoldingSet;
  60. ///
  61. /// Four public methods are available to manipulate the folding set;
  62. ///
  63. /// 1) If you have an existing node that you want add to the set but unsure
  64. /// that the node might already exist then call;
  65. ///
  66. /// MyNode *M = MyFoldingSet.GetOrInsertNode(N);
  67. ///
  68. /// If The result is equal to the input then the node has been inserted.
  69. /// Otherwise, the result is the node existing in the folding set, and the
  70. /// input can be discarded (use the result instead.)
  71. ///
  72. /// 2) If you are ready to construct a node but want to check if it already
  73. /// exists, then call FindNodeOrInsertPos with a FoldingSetNodeID of the bits to
  74. /// check;
  75. ///
  76. /// FoldingSetNodeID ID;
  77. /// ID.AddString(Name);
  78. /// ID.AddInteger(Value);
  79. /// void *InsertPoint;
  80. ///
  81. /// MyNode *M = MyFoldingSet.FindNodeOrInsertPos(ID, InsertPoint);
  82. ///
  83. /// If found then M with be non-NULL, else InsertPoint will point to where it
  84. /// should be inserted using InsertNode.
  85. ///
  86. /// 3) If you get a NULL result from FindNodeOrInsertPos then you can as a new
  87. /// node with FindNodeOrInsertPos;
  88. ///
  89. /// InsertNode(N, InsertPoint);
  90. ///
  91. /// 4) Finally, if you want to remove a node from the folding set call;
  92. ///
  93. /// bool WasRemoved = RemoveNode(N);
  94. ///
  95. /// The result indicates whether the node existed in the folding set.
  96. class FoldingSetNodeID;
  97. //===----------------------------------------------------------------------===//
  98. /// FoldingSetImpl - Implements the folding set functionality. The main
  99. /// structure is an array of buckets. Each bucket is indexed by the hash of
  100. /// the nodes it contains. The bucket itself points to the nodes contained
  101. /// in the bucket via a singly linked list. The last node in the list points
  102. /// back to the bucket to facilitate node removal.
  103. ///
  104. class FoldingSetImpl {
  105. virtual void anchor(); // Out of line virtual method.
  106. protected:
  107. /// Buckets - Array of bucket chains.
  108. ///
  109. void **Buckets;
  110. /// NumBuckets - Length of the Buckets array. Always a power of 2.
  111. ///
  112. unsigned NumBuckets;
  113. /// NumNodes - Number of nodes in the folding set. Growth occurs when NumNodes
  114. /// is greater than twice the number of buckets.
  115. unsigned NumNodes;
  116. ~FoldingSetImpl();
  117. explicit FoldingSetImpl(unsigned Log2InitSize = 6);
  118. public:
  119. //===--------------------------------------------------------------------===//
  120. /// Node - This class is used to maintain the singly linked bucket list in
  121. /// a folding set.
  122. ///
  123. class Node {
  124. private:
  125. // NextInFoldingSetBucket - next link in the bucket list.
  126. void *NextInFoldingSetBucket;
  127. public:
  128. Node() : NextInFoldingSetBucket(nullptr) {}
  129. // Accessors
  130. void *getNextInBucket() const { return NextInFoldingSetBucket; }
  131. void SetNextInBucket(void *N) { NextInFoldingSetBucket = N; }
  132. };
  133. /// clear - Remove all nodes from the folding set.
  134. void clear();
  135. /// RemoveNode - Remove a node from the folding set, returning true if one
  136. /// was removed or false if the node was not in the folding set.
  137. bool RemoveNode(Node *N);
  138. /// GetOrInsertNode - If there is an existing simple Node exactly
  139. /// equal to the specified node, return it. Otherwise, insert 'N' and return
  140. /// it instead.
  141. Node *GetOrInsertNode(Node *N);
  142. /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists,
  143. /// return it. If not, return the insertion token that will make insertion
  144. /// faster.
  145. Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos);
  146. /// InsertNode - Insert the specified node into the folding set, knowing that
  147. /// it is not already in the folding set. InsertPos must be obtained from
  148. /// FindNodeOrInsertPos.
  149. void InsertNode(Node *N, void *InsertPos);
  150. /// InsertNode - Insert the specified node into the folding set, knowing that
  151. /// it is not already in the folding set.
  152. void InsertNode(Node *N) {
  153. Node *Inserted = GetOrInsertNode(N);
  154. (void)Inserted;
  155. assert(Inserted == N && "Node already inserted!");
  156. }
  157. /// size - Returns the number of nodes in the folding set.
  158. unsigned size() const { return NumNodes; }
  159. /// empty - Returns true if there are no nodes in the folding set.
  160. bool empty() const { return NumNodes == 0; }
  161. private:
  162. /// GrowHashTable - Double the size of the hash table and rehash everything.
  163. ///
  164. void GrowHashTable();
  165. protected:
  166. /// GetNodeProfile - Instantiations of the FoldingSet template implement
  167. /// this function to gather data bits for the given node.
  168. virtual void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const = 0;
  169. /// NodeEquals - Instantiations of the FoldingSet template implement
  170. /// this function to compare the given node with the given ID.
  171. virtual bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
  172. FoldingSetNodeID &TempID) const=0;
  173. /// ComputeNodeHash - Instantiations of the FoldingSet template implement
  174. /// this function to compute a hash value for the given node.
  175. virtual unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const = 0;
  176. };
  177. //===----------------------------------------------------------------------===//
  178. template<typename T> struct FoldingSetTrait;
  179. /// DefaultFoldingSetTrait - This class provides default implementations
  180. /// for FoldingSetTrait implementations.
  181. ///
  182. template<typename T> struct DefaultFoldingSetTrait {
  183. static void Profile(const T &X, FoldingSetNodeID &ID) {
  184. X.Profile(ID);
  185. }
  186. static void Profile(T &X, FoldingSetNodeID &ID) {
  187. X.Profile(ID);
  188. }
  189. // Equals - Test if the profile for X would match ID, using TempID
  190. // to compute a temporary ID if necessary. The default implementation
  191. // just calls Profile and does a regular comparison. Implementations
  192. // can override this to provide more efficient implementations.
  193. static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
  194. FoldingSetNodeID &TempID);
  195. // ComputeHash - Compute a hash value for X, using TempID to
  196. // compute a temporary ID if necessary. The default implementation
  197. // just calls Profile and does a regular hash computation.
  198. // Implementations can override this to provide more efficient
  199. // implementations.
  200. static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID);
  201. };
  202. /// FoldingSetTrait - This trait class is used to define behavior of how
  203. /// to "profile" (in the FoldingSet parlance) an object of a given type.
  204. /// The default behavior is to invoke a 'Profile' method on an object, but
  205. /// through template specialization the behavior can be tailored for specific
  206. /// types. Combined with the FoldingSetNodeWrapper class, one can add objects
  207. /// to FoldingSets that were not originally designed to have that behavior.
  208. template<typename T> struct FoldingSetTrait
  209. : public DefaultFoldingSetTrait<T> {};
  210. template<typename T, typename Ctx> struct ContextualFoldingSetTrait;
  211. /// DefaultContextualFoldingSetTrait - Like DefaultFoldingSetTrait, but
  212. /// for ContextualFoldingSets.
  213. template<typename T, typename Ctx>
  214. struct DefaultContextualFoldingSetTrait {
  215. static void Profile(T &X, FoldingSetNodeID &ID, Ctx Context) {
  216. X.Profile(ID, Context);
  217. }
  218. static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
  219. FoldingSetNodeID &TempID, Ctx Context);
  220. static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID,
  221. Ctx Context);
  222. };
  223. /// ContextualFoldingSetTrait - Like FoldingSetTrait, but for
  224. /// ContextualFoldingSets.
  225. template<typename T, typename Ctx> struct ContextualFoldingSetTrait
  226. : public DefaultContextualFoldingSetTrait<T, Ctx> {};
  227. //===--------------------------------------------------------------------===//
  228. /// FoldingSetNodeIDRef - This class describes a reference to an interned
  229. /// FoldingSetNodeID, which can be a useful to store node id data rather
  230. /// than using plain FoldingSetNodeIDs, since the 32-element SmallVector
  231. /// is often much larger than necessary, and the possibility of heap
  232. /// allocation means it requires a non-trivial destructor call.
  233. class FoldingSetNodeIDRef {
  234. const unsigned *Data;
  235. size_t Size;
  236. public:
  237. FoldingSetNodeIDRef() : Data(nullptr), Size(0) {}
  238. FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {}
  239. /// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef,
  240. /// used to lookup the node in the FoldingSetImpl.
  241. unsigned ComputeHash() const;
  242. bool operator==(FoldingSetNodeIDRef) const;
  243. bool operator!=(FoldingSetNodeIDRef RHS) const { return !(*this == RHS); }
  244. /// Used to compare the "ordering" of two nodes as defined by the
  245. /// profiled bits and their ordering defined by memcmp().
  246. bool operator<(FoldingSetNodeIDRef) const;
  247. const unsigned *getData() const { return Data; }
  248. size_t getSize() const { return Size; }
  249. };
  250. //===--------------------------------------------------------------------===//
  251. /// FoldingSetNodeID - This class is used to gather all the unique data bits of
  252. /// a node. When all the bits are gathered this class is used to produce a
  253. /// hash value for the node.
  254. ///
  255. class FoldingSetNodeID {
  256. /// Bits - Vector of all the data bits that make the node unique.
  257. /// Use a SmallVector to avoid a heap allocation in the common case.
  258. SmallVector<unsigned, 32> Bits;
  259. public:
  260. FoldingSetNodeID() {}
  261. FoldingSetNodeID(FoldingSetNodeIDRef Ref)
  262. : Bits(Ref.getData(), Ref.getData() + Ref.getSize()) {}
  263. /// Add* - Add various data types to Bit data.
  264. ///
  265. void AddPointer(const void *Ptr);
  266. void AddInteger(signed I);
  267. void AddInteger(unsigned I);
  268. void AddInteger(long I);
  269. void AddInteger(unsigned long I);
  270. void AddInteger(long long I);
  271. void AddInteger(unsigned long long I);
  272. void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
  273. void AddString(StringRef String);
  274. void AddNodeID(const FoldingSetNodeID &ID);
  275. template <typename T>
  276. inline void Add(const T &x) { FoldingSetTrait<T>::Profile(x, *this); }
  277. /// clear - Clear the accumulated profile, allowing this FoldingSetNodeID
  278. /// object to be used to compute a new profile.
  279. inline void clear() { Bits.clear(); }
  280. /// ComputeHash - Compute a strong hash value for this FoldingSetNodeID, used
  281. /// to lookup the node in the FoldingSetImpl.
  282. unsigned ComputeHash() const;
  283. /// operator== - Used to compare two nodes to each other.
  284. ///
  285. bool operator==(const FoldingSetNodeID &RHS) const;
  286. bool operator==(const FoldingSetNodeIDRef RHS) const;
  287. bool operator!=(const FoldingSetNodeID &RHS) const { return !(*this == RHS); }
  288. bool operator!=(const FoldingSetNodeIDRef RHS) const { return !(*this ==RHS);}
  289. /// Used to compare the "ordering" of two nodes as defined by the
  290. /// profiled bits and their ordering defined by memcmp().
  291. bool operator<(const FoldingSetNodeID &RHS) const;
  292. bool operator<(const FoldingSetNodeIDRef RHS) const;
  293. /// Intern - Copy this node's data to a memory region allocated from the
  294. /// given allocator and return a FoldingSetNodeIDRef describing the
  295. /// interned data.
  296. FoldingSetNodeIDRef Intern(BumpPtrAllocator &Allocator) const;
  297. };
  298. // Convenience type to hide the implementation of the folding set.
  299. typedef FoldingSetImpl::Node FoldingSetNode;
  300. template<class T> class FoldingSetIterator;
  301. template<class T> class FoldingSetBucketIterator;
  302. // Definitions of FoldingSetTrait and ContextualFoldingSetTrait functions, which
  303. // require the definition of FoldingSetNodeID.
  304. template<typename T>
  305. inline bool
  306. DefaultFoldingSetTrait<T>::Equals(_In_ T &X, const FoldingSetNodeID &ID,
  307. unsigned /*IDHash*/,
  308. FoldingSetNodeID &TempID) {
  309. FoldingSetTrait<T>::Profile(X, TempID);
  310. return TempID == ID;
  311. }
  312. template<typename T>
  313. inline unsigned
  314. DefaultFoldingSetTrait<T>::ComputeHash(T &X, FoldingSetNodeID &TempID) {
  315. FoldingSetTrait<T>::Profile(X, TempID);
  316. return TempID.ComputeHash();
  317. }
  318. template<typename T, typename Ctx>
  319. inline bool
  320. DefaultContextualFoldingSetTrait<T, Ctx>::Equals(T &X,
  321. const FoldingSetNodeID &ID,
  322. unsigned /*IDHash*/,
  323. FoldingSetNodeID &TempID,
  324. Ctx Context) {
  325. ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context);
  326. return TempID == ID;
  327. }
  328. template<typename T, typename Ctx>
  329. inline unsigned
  330. DefaultContextualFoldingSetTrait<T, Ctx>::ComputeHash(T &X,
  331. FoldingSetNodeID &TempID,
  332. Ctx Context) {
  333. ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context);
  334. return TempID.ComputeHash();
  335. }
  336. //===----------------------------------------------------------------------===//
  337. /// FoldingSet - This template class is used to instantiate a specialized
  338. /// implementation of the folding set to the node class T. T must be a
  339. /// subclass of FoldingSetNode and implement a Profile function.
  340. ///
  341. template <class T> class FoldingSet final : public FoldingSetImpl {
  342. private:
  343. /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
  344. /// way to convert nodes into a unique specifier.
  345. void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override {
  346. T *TN = static_cast<T *>(N);
  347. FoldingSetTrait<T>::Profile(*TN, ID);
  348. }
  349. /// NodeEquals - Instantiations may optionally provide a way to compare a
  350. /// node with a specified ID.
  351. bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
  352. FoldingSetNodeID &TempID) const override {
  353. T *TN = static_cast<T *>(N);
  354. return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID);
  355. }
  356. /// ComputeNodeHash - Instantiations may optionally provide a way to compute a
  357. /// hash value directly from a node.
  358. unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const override {
  359. T *TN = static_cast<T *>(N);
  360. return FoldingSetTrait<T>::ComputeHash(*TN, TempID);
  361. }
  362. public:
  363. explicit FoldingSet(unsigned Log2InitSize = 6)
  364. : FoldingSetImpl(Log2InitSize)
  365. {}
  366. typedef FoldingSetIterator<T> iterator;
  367. iterator begin() { return iterator(Buckets); }
  368. iterator end() { return iterator(Buckets+NumBuckets); }
  369. typedef FoldingSetIterator<const T> const_iterator;
  370. const_iterator begin() const { return const_iterator(Buckets); }
  371. const_iterator end() const { return const_iterator(Buckets+NumBuckets); }
  372. typedef FoldingSetBucketIterator<T> bucket_iterator;
  373. bucket_iterator bucket_begin(unsigned hash) {
  374. return bucket_iterator(Buckets + (hash & (NumBuckets-1)));
  375. }
  376. bucket_iterator bucket_end(unsigned hash) {
  377. return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true);
  378. }
  379. /// GetOrInsertNode - If there is an existing simple Node exactly
  380. /// equal to the specified node, return it. Otherwise, insert 'N' and
  381. /// return it instead.
  382. T *GetOrInsertNode(Node *N) {
  383. return static_cast<T *>(FoldingSetImpl::GetOrInsertNode(N));
  384. }
  385. /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists,
  386. /// return it. If not, return the insertion token that will make insertion
  387. /// faster.
  388. T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
  389. return static_cast<T *>(FoldingSetImpl::FindNodeOrInsertPos(ID, InsertPos));
  390. }
  391. };
  392. //===----------------------------------------------------------------------===//
  393. /// ContextualFoldingSet - This template class is a further refinement
  394. /// of FoldingSet which provides a context argument when calling
  395. /// Profile on its nodes. Currently, that argument is fixed at
  396. /// initialization time.
  397. ///
  398. /// T must be a subclass of FoldingSetNode and implement a Profile
  399. /// function with signature
  400. /// void Profile(llvm::FoldingSetNodeID &, Ctx);
  401. template <class T, class Ctx>
  402. class ContextualFoldingSet final : public FoldingSetImpl {
  403. // Unfortunately, this can't derive from FoldingSet<T> because the
  404. // construction vtable for FoldingSet<T> requires
  405. // FoldingSet<T>::GetNodeProfile to be instantiated, which in turn
  406. // requires a single-argument T::Profile().
  407. private:
  408. Ctx Context;
  409. /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
  410. /// way to convert nodes into a unique specifier.
  411. void GetNodeProfile(FoldingSetImpl::Node *N,
  412. FoldingSetNodeID &ID) const override {
  413. T *TN = static_cast<T *>(N);
  414. ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, Context);
  415. }
  416. bool NodeEquals(FoldingSetImpl::Node *N, const FoldingSetNodeID &ID,
  417. unsigned IDHash, FoldingSetNodeID &TempID) const override {
  418. T *TN = static_cast<T *>(N);
  419. return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID,
  420. Context);
  421. }
  422. unsigned ComputeNodeHash(FoldingSetImpl::Node *N,
  423. FoldingSetNodeID &TempID) const override {
  424. T *TN = static_cast<T *>(N);
  425. return ContextualFoldingSetTrait<T, Ctx>::ComputeHash(*TN, TempID, Context);
  426. }
  427. public:
  428. explicit ContextualFoldingSet(Ctx Context, unsigned Log2InitSize = 6)
  429. : FoldingSetImpl(Log2InitSize), Context(Context)
  430. {}
  431. Ctx getContext() const { return Context; }
  432. typedef FoldingSetIterator<T> iterator;
  433. iterator begin() { return iterator(Buckets); }
  434. iterator end() { return iterator(Buckets+NumBuckets); }
  435. typedef FoldingSetIterator<const T> const_iterator;
  436. const_iterator begin() const { return const_iterator(Buckets); }
  437. const_iterator end() const { return const_iterator(Buckets+NumBuckets); }
  438. typedef FoldingSetBucketIterator<T> bucket_iterator;
  439. bucket_iterator bucket_begin(unsigned hash) {
  440. return bucket_iterator(Buckets + (hash & (NumBuckets-1)));
  441. }
  442. bucket_iterator bucket_end(unsigned hash) {
  443. return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true);
  444. }
  445. /// GetOrInsertNode - If there is an existing simple Node exactly
  446. /// equal to the specified node, return it. Otherwise, insert 'N'
  447. /// and return it instead.
  448. T *GetOrInsertNode(Node *N) {
  449. return static_cast<T *>(FoldingSetImpl::GetOrInsertNode(N));
  450. }
  451. /// FindNodeOrInsertPos - Look up the node specified by ID. If it
  452. /// exists, return it. If not, return the insertion token that will
  453. /// make insertion faster.
  454. T *FindNodeOrInsertPos(_In_ const FoldingSetNodeID &ID, void *&InsertPos) {
  455. return static_cast<T *>(FoldingSetImpl::FindNodeOrInsertPos(ID, InsertPos));
  456. }
  457. };
  458. //===----------------------------------------------------------------------===//
  459. /// FoldingSetVector - This template class combines a FoldingSet and a vector
  460. /// to provide the interface of FoldingSet but with deterministic iteration
  461. /// order based on the insertion order. T must be a subclass of FoldingSetNode
  462. /// and implement a Profile function.
  463. template <class T, class VectorT = SmallVector<T*, 8> >
  464. class FoldingSetVector {
  465. FoldingSet<T> Set;
  466. VectorT Vector;
  467. public:
  468. explicit FoldingSetVector(unsigned Log2InitSize = 6)
  469. : Set(Log2InitSize) {
  470. }
  471. typedef pointee_iterator<typename VectorT::iterator> iterator;
  472. iterator begin() { return Vector.begin(); }
  473. iterator end() { return Vector.end(); }
  474. typedef pointee_iterator<typename VectorT::const_iterator> const_iterator;
  475. const_iterator begin() const { return Vector.begin(); }
  476. const_iterator end() const { return Vector.end(); }
  477. /// clear - Remove all nodes from the folding set.
  478. void clear() { Set.clear(); Vector.clear(); }
  479. /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists,
  480. /// return it. If not, return the insertion token that will make insertion
  481. /// faster.
  482. T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
  483. return Set.FindNodeOrInsertPos(ID, InsertPos);
  484. }
  485. /// GetOrInsertNode - If there is an existing simple Node exactly
  486. /// equal to the specified node, return it. Otherwise, insert 'N' and
  487. /// return it instead.
  488. T *GetOrInsertNode(T *N) {
  489. T *Result = Set.GetOrInsertNode(N);
  490. if (Result == N) Vector.push_back(N);
  491. return Result;
  492. }
  493. /// InsertNode - Insert the specified node into the folding set, knowing that
  494. /// it is not already in the folding set. InsertPos must be obtained from
  495. /// FindNodeOrInsertPos.
  496. void InsertNode(T *N, void *InsertPos) {
  497. Set.InsertNode(N, InsertPos);
  498. Vector.push_back(N);
  499. }
  500. /// InsertNode - Insert the specified node into the folding set, knowing that
  501. /// it is not already in the folding set.
  502. void InsertNode(T *N) {
  503. Set.InsertNode(N);
  504. Vector.push_back(N);
  505. }
  506. /// size - Returns the number of nodes in the folding set.
  507. unsigned size() const { return Set.size(); }
  508. /// empty - Returns true if there are no nodes in the folding set.
  509. bool empty() const { return Set.empty(); }
  510. };
  511. //===----------------------------------------------------------------------===//
  512. /// FoldingSetIteratorImpl - This is the common iterator support shared by all
  513. /// folding sets, which knows how to walk the folding set hash table.
  514. class FoldingSetIteratorImpl {
  515. protected:
  516. FoldingSetNode *NodePtr;
  517. FoldingSetIteratorImpl(void **Bucket);
  518. void advance();
  519. public:
  520. bool operator==(const FoldingSetIteratorImpl &RHS) const {
  521. return NodePtr == RHS.NodePtr;
  522. }
  523. bool operator!=(const FoldingSetIteratorImpl &RHS) const {
  524. return NodePtr != RHS.NodePtr;
  525. }
  526. };
  527. template<class T>
  528. class FoldingSetIterator : public FoldingSetIteratorImpl {
  529. public:
  530. explicit FoldingSetIterator(void **Bucket) : FoldingSetIteratorImpl(Bucket) {}
  531. T &operator*() const {
  532. return *static_cast<T*>(NodePtr);
  533. }
  534. T *operator->() const {
  535. return static_cast<T*>(NodePtr);
  536. }
  537. inline FoldingSetIterator &operator++() { // Preincrement
  538. advance();
  539. return *this;
  540. }
  541. FoldingSetIterator operator++(int) { // Postincrement
  542. FoldingSetIterator tmp = *this; ++*this; return tmp;
  543. }
  544. };
  545. //===----------------------------------------------------------------------===//
  546. /// FoldingSetBucketIteratorImpl - This is the common bucket iterator support
  547. /// shared by all folding sets, which knows how to walk a particular bucket
  548. /// of a folding set hash table.
  549. class FoldingSetBucketIteratorImpl {
  550. protected:
  551. void *Ptr;
  552. explicit FoldingSetBucketIteratorImpl(void **Bucket);
  553. FoldingSetBucketIteratorImpl(void **Bucket, bool)
  554. : Ptr(Bucket) {}
  555. void advance() {
  556. void *Probe = static_cast<FoldingSetNode*>(Ptr)->getNextInBucket();
  557. uintptr_t x = reinterpret_cast<uintptr_t>(Probe) & ~0x1;
  558. Ptr = reinterpret_cast<void*>(x);
  559. }
  560. public:
  561. bool operator==(const FoldingSetBucketIteratorImpl &RHS) const {
  562. return Ptr == RHS.Ptr;
  563. }
  564. bool operator!=(const FoldingSetBucketIteratorImpl &RHS) const {
  565. return Ptr != RHS.Ptr;
  566. }
  567. };
  568. template<class T>
  569. class FoldingSetBucketIterator : public FoldingSetBucketIteratorImpl {
  570. public:
  571. explicit FoldingSetBucketIterator(void **Bucket) :
  572. FoldingSetBucketIteratorImpl(Bucket) {}
  573. FoldingSetBucketIterator(void **Bucket, bool) :
  574. FoldingSetBucketIteratorImpl(Bucket, true) {}
  575. T &operator*() const { return *static_cast<T*>(Ptr); }
  576. T *operator->() const { return static_cast<T*>(Ptr); }
  577. inline FoldingSetBucketIterator &operator++() { // Preincrement
  578. advance();
  579. return *this;
  580. }
  581. FoldingSetBucketIterator operator++(int) { // Postincrement
  582. FoldingSetBucketIterator tmp = *this; ++*this; return tmp;
  583. }
  584. };
  585. //===----------------------------------------------------------------------===//
  586. /// FoldingSetNodeWrapper - This template class is used to "wrap" arbitrary
  587. /// types in an enclosing object so that they can be inserted into FoldingSets.
  588. template <typename T>
  589. class FoldingSetNodeWrapper : public FoldingSetNode {
  590. T data;
  591. public:
  592. template <typename... Ts>
  593. explicit FoldingSetNodeWrapper(Ts &&... Args)
  594. : data(std::forward<Ts>(Args)...) {}
  595. void Profile(FoldingSetNodeID &ID) { FoldingSetTrait<T>::Profile(data, ID); }
  596. T &getValue() { return data; }
  597. const T &getValue() const { return data; }
  598. operator T&() { return data; }
  599. operator const T&() const { return data; }
  600. };
  601. //===----------------------------------------------------------------------===//
  602. /// FastFoldingSetNode - This is a subclass of FoldingSetNode which stores
  603. /// a FoldingSetNodeID value rather than requiring the node to recompute it
  604. /// each time it is needed. This trades space for speed (which can be
  605. /// significant if the ID is long), and it also permits nodes to drop
  606. /// information that would otherwise only be required for recomputing an ID.
  607. class FastFoldingSetNode : public FoldingSetNode {
  608. FoldingSetNodeID FastID;
  609. protected:
  610. explicit FastFoldingSetNode(const FoldingSetNodeID &ID) : FastID(ID) {}
  611. public:
  612. void Profile(FoldingSetNodeID &ID) const {
  613. ID.AddNodeID(FastID);
  614. }
  615. };
  616. // //
  617. ///////////////////////////////////////////////////////////////////////////////
  618. // Partial specializations of FoldingSetTrait.
  619. template<typename T> struct FoldingSetTrait<T*> {
  620. static inline void Profile(T *X, FoldingSetNodeID &ID) {
  621. ID.AddPointer(X);
  622. }
  623. };
  624. template <typename T1, typename T2>
  625. struct FoldingSetTrait<std::pair<T1, T2>> {
  626. static inline void Profile(const std::pair<T1, T2> &P,
  627. llvm::FoldingSetNodeID &ID) {
  628. ID.Add(P.first);
  629. ID.Add(P.second);
  630. }
  631. };
  632. } // End of namespace llvm.
  633. #endif