@@ -113,8 +113,6 @@ class StringRef;
113113// / This class provides default implementations for FoldingSetTrait
114114// / implementations.
115115template <typename T> struct DefaultFoldingSetTrait {
116- struct ContextStorage {};
117-
118116 static void Profile (const T &X, FoldingSetNodeID &ID ) { X.Profile (ID ); }
119117 static void Profile (T &X, FoldingSetNodeID &ID ) { X.Profile (ID ); }
120118
@@ -144,12 +142,6 @@ struct FoldingSetTrait : public DefaultFoldingSetTrait<T> {};
144142
145143// / Like DefaultFoldingSetTrait, but for ContextualFoldingSets.
146144template <typename T, typename Ctx> struct DefaultContextualFoldingSetTrait {
147- struct ContextStorage {
148- Ctx Context;
149- explicit ContextStorage (Ctx Context) : Context(Context) {}
150- Ctx getContext () const { return Context; }
151- };
152-
153145 static void Profile (T &X, FoldingSetNodeID &ID , Ctx Context) {
154146 X.Profile (ID , Context);
155147 }
@@ -441,50 +433,11 @@ inline unsigned DefaultContextualFoldingSetTrait<T, Ctx>::ComputeHash(
441433// ===----------------------------------------------------------------------===//
442434// / An implementation detail that lets us share code between FoldingSet and
443435// / ContextualFoldingSet.
444- template <class T , class Trait = FoldingSetTrait<T>>
445- class FoldingSetImpl : public FoldingSetBase , public Trait ::ContextStorage {
446- static constexpr FoldingSetBase::FoldingSetInfo Info = {
447- // GetNodeProfile
448- [](const FoldingSetBase *Base, FoldingSetNode *N, FoldingSetNodeID &ID ) {
449- if constexpr (std::is_empty_v<typename Trait::ContextStorage>)
450- Trait::Profile (*static_cast <T *>(N), ID );
451- else
452- Trait::Profile (
453- *static_cast <T *>(N), ID ,
454- static_cast <const FoldingSetImpl *>(Base)->getContext ());
455- },
456- // NodeEquals
457- [](const FoldingSetBase *Base, FoldingSetNode *N,
458- const FoldingSetNodeID &ID , unsigned IDHash,
459- FoldingSetNodeID &TempID) {
460- if constexpr (std::is_empty_v<typename Trait::ContextStorage>)
461- return Trait::Equals (*static_cast <T *>(N), ID , IDHash, TempID);
462- else
463- return Trait::Equals (
464- *static_cast <T *>(N), ID , IDHash, TempID,
465- static_cast <const FoldingSetImpl *>(Base)->getContext ());
466- },
467- // ComputeNodeHash
468- [](const FoldingSetBase *Base, FoldingSetNode *N,
469- FoldingSetNodeID &TempID) {
470- if constexpr (std::is_empty_v<typename Trait::ContextStorage>)
471- return Trait::ComputeHash (*static_cast <T *>(N), TempID);
472- else
473- return Trait::ComputeHash (
474- *static_cast <T *>(N), TempID,
475- static_cast <const FoldingSetImpl *>(Base)->getContext ());
476- }};
477-
478- public:
479- explicit FoldingSetImpl (unsigned Log2InitSize = 6 )
436+ template <class Derived , class T > class FoldingSetImpl : public FoldingSetBase {
437+ protected:
438+ explicit FoldingSetImpl (unsigned Log2InitSize)
480439 : FoldingSetBase(Log2InitSize) {}
481440
482- template <typename C, typename = std::enable_if_t <std::is_constructible_v<
483- typename Trait::ContextStorage, C>>>
484- explicit FoldingSetImpl (C &&Context, unsigned Log2InitSize = 6 )
485- : FoldingSetBase(Log2InitSize),
486- Trait::ContextStorage(std::forward<C>(Context)) {}
487-
488441 FoldingSetImpl (FoldingSetImpl &&Arg) = default ;
489442 FoldingSetImpl &operator =(FoldingSetImpl &&RHS ) = default ;
490443 ~FoldingSetImpl () = default ;
@@ -503,7 +456,9 @@ class FoldingSetImpl : public FoldingSetBase, public Trait::ContextStorage {
503456 // / Increase the number of buckets such that adding the \p EltCount th node
504457 // / won't cause a rebucket operation. reserve is permitted to allocate more
505458 // / space than requested by EltCount.
506- void reserve (unsigned EltCount) { FoldingSetBase::reserve (EltCount, Info); }
459+ void reserve (unsigned EltCount) {
460+ FoldingSetBase::reserve (EltCount, Derived::getFoldingSetInfo ());
461+ }
507462
508463 // / Remove a node from the folding set, returning true if one
509464 // / was removed or false if the node was not in the folding set.
@@ -512,21 +467,22 @@ class FoldingSetImpl : public FoldingSetBase, public Trait::ContextStorage {
512467 // / If there is an existing simple Node exactly equal to the specified node,
513468 // / return it. Otherwise, insert 'N' and return it instead.
514469 T *GetOrInsertNode (T *N) {
515- return static_cast <T *>(FoldingSetBase::GetOrInsertNode (N, Info));
470+ return static_cast <T *>(
471+ FoldingSetBase::GetOrInsertNode (N, Derived::getFoldingSetInfo ()));
516472 }
517473
518474 // / Look up the node specified by ID. If it exists, return it. If not,
519475 // / return the insertion token that will make insertion faster.
520476 T *FindNodeOrInsertPos (const FoldingSetNodeID &ID , void *&InsertPos) {
521- return static_cast <T *>(
522- FoldingSetBase::FindNodeOrInsertPos ( ID , InsertPos, Info ));
477+ return static_cast <T *>(FoldingSetBase::FindNodeOrInsertPos (
478+ ID , InsertPos, Derived::getFoldingSetInfo () ));
523479 }
524480
525481 // / Insert the specified node into the folding set, knowing that
526482 // / it is not already in the folding set. InsertPos must be obtained from
527483 // / FindNodeOrInsertPos.
528484 void InsertNode (T *N, void *InsertPos) {
529- FoldingSetBase::InsertNode (N, InsertPos, Info );
485+ FoldingSetBase::InsertNode (N, InsertPos, Derived::getFoldingSetInfo () );
530486 }
531487
532488 // / Insert the specified node into the folding set, knowing that it is not
@@ -547,8 +503,47 @@ class FoldingSetImpl : public FoldingSetBase, public Trait::ContextStorage {
547503// / moved-from state is not a valid state for anything other than
548504// / move-assigning and destroying. This is primarily to enable movable APIs
549505// / that incorporate these objects.
550- template <class T , class Trait = FoldingSetTrait<T>>
551- using FoldingSet = FoldingSetImpl<T, Trait>;
506+ template <class T > class FoldingSet : public FoldingSetImpl <FoldingSet<T>, T> {
507+ using Super = FoldingSetImpl<FoldingSet, T>;
508+ using Node = typename Super::Node;
509+
510+ // / Each instantiation of the FoldingSet needs to provide a
511+ // / way to convert nodes into a unique specifier.
512+ static void GetNodeProfile (const FoldingSetBase *, Node *N,
513+ FoldingSetNodeID &ID ) {
514+ T *TN = static_cast <T *>(N);
515+ FoldingSetTrait<T>::Profile (*TN , ID );
516+ }
517+
518+ // / Instantiations may optionally provide a way to compare a
519+ // / node with a specified ID.
520+ static bool NodeEquals (const FoldingSetBase *, Node *N,
521+ const FoldingSetNodeID &ID , unsigned IDHash,
522+ FoldingSetNodeID &TempID) {
523+ T *TN = static_cast <T *>(N);
524+ return FoldingSetTrait<T>::Equals (*TN , ID , IDHash, TempID);
525+ }
526+
527+ // / Instantiations may optionally provide a way to compute a
528+ // / hash value directly from a node.
529+ static unsigned ComputeNodeHash (const FoldingSetBase *, Node *N,
530+ FoldingSetNodeID &TempID) {
531+ T *TN = static_cast <T *>(N);
532+ return FoldingSetTrait<T>::ComputeHash (*TN , TempID);
533+ }
534+
535+ static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo () {
536+ static constexpr FoldingSetBase::FoldingSetInfo Info = {
537+ GetNodeProfile, NodeEquals, ComputeNodeHash};
538+ return Info;
539+ }
540+ friend Super;
541+
542+ public:
543+ explicit FoldingSet (unsigned Log2InitSize = 6 ) : Super(Log2InitSize) {}
544+ FoldingSet (FoldingSet &&Arg) = default ;
545+ FoldingSet &operator =(FoldingSet &&RHS ) = default ;
546+ };
552547
553548// ===----------------------------------------------------------------------===//
554549// / This template class is a further refinement of FoldingSet which provides a
@@ -559,8 +554,58 @@ using FoldingSet = FoldingSetImpl<T, Trait>;
559554// / function with signature
560555// / void Profile(FoldingSetNodeID &, Ctx);
561556template <class T , class Ctx >
562- using ContextualFoldingSet =
563- FoldingSetImpl<T, ContextualFoldingSetTrait<T, Ctx>>;
557+ class ContextualFoldingSet
558+ : public FoldingSetImpl<ContextualFoldingSet<T, Ctx>, T> {
559+ // Unfortunately, this can't derive from FoldingSet<T> because the
560+ // construction of the vtable for FoldingSet<T> requires
561+ // FoldingSet<T>::GetNodeProfile to be instantiated, which in turn
562+ // requires a single-argument T::Profile().
563+
564+ using Super = FoldingSetImpl<ContextualFoldingSet, T>;
565+ using Node = typename Super::Node;
566+
567+ Ctx Context;
568+
569+ static const Ctx &getContext (const FoldingSetBase *Base) {
570+ return static_cast <const ContextualFoldingSet *>(Base)->Context ;
571+ }
572+
573+ // / Each instantiatation of the FoldingSet needs to provide a way to convert
574+ // / nodes into a unique specifier.
575+ static void GetNodeProfile (const FoldingSetBase *Base, Node *N,
576+ FoldingSetNodeID &ID ) {
577+ T *TN = static_cast <T *>(N);
578+ ContextualFoldingSetTrait<T, Ctx>::Profile (*TN , ID , getContext (Base));
579+ }
580+
581+ static bool NodeEquals (const FoldingSetBase *Base, Node *N,
582+ const FoldingSetNodeID &ID , unsigned IDHash,
583+ FoldingSetNodeID &TempID) {
584+ T *TN = static_cast <T *>(N);
585+ return ContextualFoldingSetTrait<T, Ctx>::Equals (*TN , ID , IDHash, TempID,
586+ getContext (Base));
587+ }
588+
589+ static unsigned ComputeNodeHash (const FoldingSetBase *Base, Node *N,
590+ FoldingSetNodeID &TempID) {
591+ T *TN = static_cast <T *>(N);
592+ return ContextualFoldingSetTrait<T, Ctx>::ComputeHash (*TN , TempID,
593+ getContext (Base));
594+ }
595+
596+ static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo () {
597+ static constexpr FoldingSetBase::FoldingSetInfo Info = {
598+ GetNodeProfile, NodeEquals, ComputeNodeHash};
599+ return Info;
600+ }
601+ friend Super;
602+
603+ public:
604+ explicit ContextualFoldingSet (Ctx Context, unsigned Log2InitSize = 6 )
605+ : Super(Log2InitSize), Context(Context) {}
606+
607+ Ctx getContext () const { return Context; }
608+ };
564609
565610// ===----------------------------------------------------------------------===//
566611// / This template class combines a FoldingSet and a vector to provide the
0 commit comments