Coverage Report

Created: 2020-06-26 05:44

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