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