Home | History | Annotate | Download | only in ADT
      1 //===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- 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 the PointerUnion class, which is a discriminated union of
     11 // pointer types.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_ADT_POINTERUNION_H
     16 #define LLVM_ADT_POINTERUNION_H
     17 
     18 #include "llvm/ADT/PointerIntPair.h"
     19 
     20 namespace llvm {
     21 
     22   template <typename T>
     23   struct PointerUnionTypeSelectorReturn {
     24     typedef T Return;
     25   };
     26 
     27   /// \brief Get a type based on whether two types are the same or not. For:
     28   /// @code
     29   /// typedef typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return Ret;
     30   /// @endcode
     31   /// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
     32   template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
     33   struct PointerUnionTypeSelector {
     34     typedef typename PointerUnionTypeSelectorReturn<RET_NE>::Return Return;
     35   };
     36 
     37   template <typename T, typename RET_EQ, typename RET_NE>
     38   struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
     39     typedef typename PointerUnionTypeSelectorReturn<RET_EQ>::Return Return;
     40   };
     41 
     42   template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
     43   struct PointerUnionTypeSelectorReturn<
     44                             PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE> > {
     45     typedef typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return
     46         Return;
     47   };
     48 
     49   /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
     50   /// for the two template arguments.
     51   template <typename PT1, typename PT2>
     52   class PointerUnionUIntTraits {
     53   public:
     54     static inline void *getAsVoidPointer(void *P) { return P; }
     55     static inline void *getFromVoidPointer(void *P) { return P; }
     56     enum {
     57       PT1BitsAv = (int)(PointerLikeTypeTraits<PT1>::NumLowBitsAvailable),
     58       PT2BitsAv = (int)(PointerLikeTypeTraits<PT2>::NumLowBitsAvailable),
     59       NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv
     60     };
     61   };
     62 
     63   /// PointerUnion - This implements a discriminated union of two pointer types,
     64   /// and keeps the discriminator bit-mangled into the low bits of the pointer.
     65   /// This allows the implementation to be extremely efficient in space, but
     66   /// permits a very natural and type-safe API.
     67   ///
     68   /// Common use patterns would be something like this:
     69   ///    PointerUnion<int*, float*> P;
     70   ///    P = (int*)0;
     71   ///    printf("%d %d", P.is<int*>(), P.is<float*>());  // prints "1 0"
     72   ///    X = P.get<int*>();     // ok.
     73   ///    Y = P.get<float*>();   // runtime assertion failure.
     74   ///    Z = P.get<double*>();  // runtime assertion failure (regardless of tag)
     75   ///    P = (float*)0;
     76   ///    Y = P.get<float*>();   // ok.
     77   ///    X = P.get<int*>();     // runtime assertion failure.
     78   template <typename PT1, typename PT2>
     79   class PointerUnion {
     80   public:
     81     typedef PointerIntPair<void*, 1, bool,
     82                            PointerUnionUIntTraits<PT1,PT2> > ValTy;
     83   private:
     84     ValTy Val;
     85 
     86     struct IsPT1 {
     87       static const int Num = 0;
     88     };
     89     struct IsPT2 {
     90       static const int Num = 1;
     91     };
     92     template <typename T>
     93     struct UNION_DOESNT_CONTAIN_TYPE { };
     94 
     95   public:
     96     PointerUnion() {}
     97 
     98     PointerUnion(PT1 V) : Val(
     99       const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(V))) {
    100     }
    101     PointerUnion(PT2 V) : Val(
    102       const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)), 1) {
    103     }
    104 
    105     /// isNull - Return true if the pointer held in the union is null,
    106     /// regardless of which type it is.
    107     bool isNull() const {
    108       // Convert from the void* to one of the pointer types, to make sure that
    109       // we recursively strip off low bits if we have a nested PointerUnion.
    110       return !PointerLikeTypeTraits<PT1>::getFromVoidPointer(Val.getPointer());
    111     }
    112     operator bool() const { return !isNull(); }
    113 
    114     /// is<T>() return true if the Union currently holds the type matching T.
    115     template<typename T>
    116     int is() const {
    117       typedef typename
    118         ::llvm::PointerUnionTypeSelector<PT1, T, IsPT1,
    119           ::llvm::PointerUnionTypeSelector<PT2, T, IsPT2,
    120                                     UNION_DOESNT_CONTAIN_TYPE<T> > >::Return Ty;
    121       int TyNo = Ty::Num;
    122       return static_cast<int>(Val.getInt()) == TyNo;
    123     }
    124 
    125     /// get<T>() - Return the value of the specified pointer type. If the
    126     /// specified pointer type is incorrect, assert.
    127     template<typename T>
    128     T get() const {
    129       assert(is<T>() && "Invalid accessor called");
    130       return PointerLikeTypeTraits<T>::getFromVoidPointer(Val.getPointer());
    131     }
    132 
    133     /// dyn_cast<T>() - If the current value is of the specified pointer type,
    134     /// return it, otherwise return null.
    135     template<typename T>
    136     T dyn_cast() const {
    137       if (is<T>()) return get<T>();
    138       return T();
    139     }
    140 
    141     /// \brief If the union is set to the first pointer type get an address
    142     /// pointing to it.
    143     PT1 const *getAddrOfPtr1() const {
    144       return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
    145     }
    146 
    147     /// \brief If the union is set to the first pointer type get an address
    148     /// pointing to it.
    149     PT1 *getAddrOfPtr1() {
    150       assert(is<PT1>() && "Val is not the first pointer");
    151       assert(get<PT1>() == Val.getPointer() &&
    152          "Can't get the address because PointerLikeTypeTraits changes the ptr");
    153       return (PT1 *)Val.getAddrOfPointer();
    154     }
    155 
    156     /// Assignment operators - Allow assigning into this union from either
    157     /// pointer type, setting the discriminator to remember what it came from.
    158     const PointerUnion &operator=(const PT1 &RHS) {
    159       Val.initWithPointer(
    160          const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS)));
    161       return *this;
    162     }
    163     const PointerUnion &operator=(const PT2 &RHS) {
    164       Val.setPointerAndInt(
    165         const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)),
    166         1);
    167       return *this;
    168     }
    169 
    170     void *getOpaqueValue() const { return Val.getOpaqueValue(); }
    171     static inline PointerUnion getFromOpaqueValue(void *VP) {
    172       PointerUnion V;
    173       V.Val = ValTy::getFromOpaqueValue(VP);
    174       return V;
    175     }
    176   };
    177 
    178   // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
    179   // # low bits available = min(PT1bits,PT2bits)-1.
    180   template<typename PT1, typename PT2>
    181   class PointerLikeTypeTraits<PointerUnion<PT1, PT2> > {
    182   public:
    183     static inline void *
    184     getAsVoidPointer(const PointerUnion<PT1, PT2> &P) {
    185       return P.getOpaqueValue();
    186     }
    187     static inline PointerUnion<PT1, PT2>
    188     getFromVoidPointer(void *P) {
    189       return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
    190     }
    191 
    192     // The number of bits available are the min of the two pointer types.
    193     enum {
    194       NumLowBitsAvailable =
    195         PointerLikeTypeTraits<typename PointerUnion<PT1,PT2>::ValTy>
    196           ::NumLowBitsAvailable
    197     };
    198   };
    199 
    200 
    201   /// PointerUnion3 - This is a pointer union of three pointer types.  See
    202   /// documentation for PointerUnion for usage.
    203   template <typename PT1, typename PT2, typename PT3>
    204   class PointerUnion3 {
    205   public:
    206     typedef PointerUnion<PT1, PT2> InnerUnion;
    207     typedef PointerUnion<InnerUnion, PT3> ValTy;
    208   private:
    209     ValTy Val;
    210 
    211     struct IsInnerUnion {
    212       ValTy Val;
    213       IsInnerUnion(ValTy val) : Val(val) { }
    214       template<typename T>
    215       int is() const {
    216         return Val.template is<InnerUnion>() &&
    217                Val.template get<InnerUnion>().template is<T>();
    218       }
    219       template<typename T>
    220       T get() const {
    221         return Val.template get<InnerUnion>().template get<T>();
    222       }
    223     };
    224 
    225     struct IsPT3 {
    226       ValTy Val;
    227       IsPT3(ValTy val) : Val(val) { }
    228       template<typename T>
    229       int is() const {
    230         return Val.template is<T>();
    231       }
    232       template<typename T>
    233       T get() const {
    234         return Val.template get<T>();
    235       }
    236     };
    237 
    238   public:
    239     PointerUnion3() {}
    240 
    241     PointerUnion3(PT1 V) {
    242       Val = InnerUnion(V);
    243     }
    244     PointerUnion3(PT2 V) {
    245       Val = InnerUnion(V);
    246     }
    247     PointerUnion3(PT3 V) {
    248       Val = V;
    249     }
    250 
    251     /// isNull - Return true if the pointer held in the union is null,
    252     /// regardless of which type it is.
    253     bool isNull() const { return Val.isNull(); }
    254     operator bool() const { return !isNull(); }
    255 
    256     /// is<T>() return true if the Union currently holds the type matching T.
    257     template<typename T>
    258     int is() const {
    259       // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
    260       typedef typename
    261         ::llvm::PointerUnionTypeSelector<PT1, T, IsInnerUnion,
    262           ::llvm::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3 >
    263                                                                    >::Return Ty;
    264       return Ty(Val).template is<T>();
    265     }
    266 
    267     /// get<T>() - Return the value of the specified pointer type. If the
    268     /// specified pointer type is incorrect, assert.
    269     template<typename T>
    270     T get() const {
    271       assert(is<T>() && "Invalid accessor called");
    272       // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
    273       typedef typename
    274         ::llvm::PointerUnionTypeSelector<PT1, T, IsInnerUnion,
    275           ::llvm::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3 >
    276                                                                    >::Return Ty;
    277       return Ty(Val).template get<T>();
    278     }
    279 
    280     /// dyn_cast<T>() - If the current value is of the specified pointer type,
    281     /// return it, otherwise return null.
    282     template<typename T>
    283     T dyn_cast() const {
    284       if (is<T>()) return get<T>();
    285       return T();
    286     }
    287 
    288     /// Assignment operators - Allow assigning into this union from either
    289     /// pointer type, setting the discriminator to remember what it came from.
    290     const PointerUnion3 &operator=(const PT1 &RHS) {
    291       Val = InnerUnion(RHS);
    292       return *this;
    293     }
    294     const PointerUnion3 &operator=(const PT2 &RHS) {
    295       Val = InnerUnion(RHS);
    296       return *this;
    297     }
    298     const PointerUnion3 &operator=(const PT3 &RHS) {
    299       Val = RHS;
    300       return *this;
    301     }
    302 
    303     void *getOpaqueValue() const { return Val.getOpaqueValue(); }
    304     static inline PointerUnion3 getFromOpaqueValue(void *VP) {
    305       PointerUnion3 V;
    306       V.Val = ValTy::getFromOpaqueValue(VP);
    307       return V;
    308     }
    309   };
    310 
    311   // Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
    312   // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
    313   template<typename PT1, typename PT2, typename PT3>
    314   class PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3> > {
    315   public:
    316     static inline void *
    317     getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) {
    318       return P.getOpaqueValue();
    319     }
    320     static inline PointerUnion3<PT1, PT2, PT3>
    321     getFromVoidPointer(void *P) {
    322       return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
    323     }
    324 
    325     // The number of bits available are the min of the two pointer types.
    326     enum {
    327       NumLowBitsAvailable =
    328         PointerLikeTypeTraits<typename PointerUnion3<PT1, PT2, PT3>::ValTy>
    329           ::NumLowBitsAvailable
    330     };
    331   };
    332 
    333   /// PointerUnion4 - This is a pointer union of four pointer types.  See
    334   /// documentation for PointerUnion for usage.
    335   template <typename PT1, typename PT2, typename PT3, typename PT4>
    336   class PointerUnion4 {
    337   public:
    338     typedef PointerUnion<PT1, PT2> InnerUnion1;
    339     typedef PointerUnion<PT3, PT4> InnerUnion2;
    340     typedef PointerUnion<InnerUnion1, InnerUnion2> ValTy;
    341   private:
    342     ValTy Val;
    343   public:
    344     PointerUnion4() {}
    345 
    346     PointerUnion4(PT1 V) {
    347       Val = InnerUnion1(V);
    348     }
    349     PointerUnion4(PT2 V) {
    350       Val = InnerUnion1(V);
    351     }
    352     PointerUnion4(PT3 V) {
    353       Val = InnerUnion2(V);
    354     }
    355     PointerUnion4(PT4 V) {
    356       Val = InnerUnion2(V);
    357     }
    358 
    359     /// isNull - Return true if the pointer held in the union is null,
    360     /// regardless of which type it is.
    361     bool isNull() const { return Val.isNull(); }
    362     operator bool() const { return !isNull(); }
    363 
    364     /// is<T>() return true if the Union currently holds the type matching T.
    365     template<typename T>
    366     int is() const {
    367       // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
    368       typedef typename
    369         ::llvm::PointerUnionTypeSelector<PT1, T, InnerUnion1,
    370           ::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1, InnerUnion2 >
    371                                                                    >::Return Ty;
    372       return Val.template is<Ty>() &&
    373              Val.template get<Ty>().template is<T>();
    374     }
    375 
    376     /// get<T>() - Return the value of the specified pointer type. If the
    377     /// specified pointer type is incorrect, assert.
    378     template<typename T>
    379     T get() const {
    380       assert(is<T>() && "Invalid accessor called");
    381       // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
    382       typedef typename
    383         ::llvm::PointerUnionTypeSelector<PT1, T, InnerUnion1,
    384           ::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1, InnerUnion2 >
    385                                                                    >::Return Ty;
    386       return Val.template get<Ty>().template get<T>();
    387     }
    388 
    389     /// dyn_cast<T>() - If the current value is of the specified pointer type,
    390     /// return it, otherwise return null.
    391     template<typename T>
    392     T dyn_cast() const {
    393       if (is<T>()) return get<T>();
    394       return T();
    395     }
    396 
    397     /// Assignment operators - Allow assigning into this union from either
    398     /// pointer type, setting the discriminator to remember what it came from.
    399     const PointerUnion4 &operator=(const PT1 &RHS) {
    400       Val = InnerUnion1(RHS);
    401       return *this;
    402     }
    403     const PointerUnion4 &operator=(const PT2 &RHS) {
    404       Val = InnerUnion1(RHS);
    405       return *this;
    406     }
    407     const PointerUnion4 &operator=(const PT3 &RHS) {
    408       Val = InnerUnion2(RHS);
    409       return *this;
    410     }
    411     const PointerUnion4 &operator=(const PT4 &RHS) {
    412       Val = InnerUnion2(RHS);
    413       return *this;
    414     }
    415 
    416     void *getOpaqueValue() const { return Val.getOpaqueValue(); }
    417     static inline PointerUnion4 getFromOpaqueValue(void *VP) {
    418       PointerUnion4 V;
    419       V.Val = ValTy::getFromOpaqueValue(VP);
    420       return V;
    421     }
    422   };
    423 
    424   // Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has
    425   // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
    426   template<typename PT1, typename PT2, typename PT3, typename PT4>
    427   class PointerLikeTypeTraits<PointerUnion4<PT1, PT2, PT3, PT4> > {
    428   public:
    429     static inline void *
    430     getAsVoidPointer(const PointerUnion4<PT1, PT2, PT3, PT4> &P) {
    431       return P.getOpaqueValue();
    432     }
    433     static inline PointerUnion4<PT1, PT2, PT3, PT4>
    434     getFromVoidPointer(void *P) {
    435       return PointerUnion4<PT1, PT2, PT3, PT4>::getFromOpaqueValue(P);
    436     }
    437 
    438     // The number of bits available are the min of the two pointer types.
    439     enum {
    440       NumLowBitsAvailable =
    441         PointerLikeTypeTraits<typename PointerUnion4<PT1, PT2, PT3, PT4>::ValTy>
    442           ::NumLowBitsAvailable
    443     };
    444   };
    445 }
    446 
    447 #endif
    448