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 = PointerLikeTypeTraits<PT1>::NumLowBitsAvailable,
     58       PT2BitsAv = 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) {
     99       Val.setPointer(
    100          const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(V)));
    101       Val.setInt(0);
    102     }
    103     PointerUnion(PT2 V) {
    104       Val.setPointer(
    105          const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)));
    106       Val.setInt(1);
    107     }
    108 
    109     /// isNull - Return true if the pointer held in the union is null,
    110     /// regardless of which type it is.
    111     bool isNull() const {
    112       // Convert from the void* to one of the pointer types, to make sure that
    113       // we recursively strip off low bits if we have a nested PointerUnion.
    114       return !PointerLikeTypeTraits<PT1>::getFromVoidPointer(Val.getPointer());
    115     }
    116     operator bool() const { return !isNull(); }
    117 
    118     /// is<T>() return true if the Union currently holds the type matching T.
    119     template<typename T>
    120     int is() const {
    121       typedef typename
    122         ::llvm::PointerUnionTypeSelector<PT1, T, IsPT1,
    123           ::llvm::PointerUnionTypeSelector<PT2, T, IsPT2,
    124                                     UNION_DOESNT_CONTAIN_TYPE<T> > >::Return Ty;
    125       int TyNo = Ty::Num;
    126       return static_cast<int>(Val.getInt()) == TyNo;
    127     }
    128 
    129     /// get<T>() - Return the value of the specified pointer type. If the
    130     /// specified pointer type is incorrect, assert.
    131     template<typename T>
    132     T get() const {
    133       assert(is<T>() && "Invalid accessor called");
    134       return PointerLikeTypeTraits<T>::getFromVoidPointer(Val.getPointer());
    135     }
    136 
    137     /// dyn_cast<T>() - If the current value is of the specified pointer type,
    138     /// return it, otherwise return null.
    139     template<typename T>
    140     T dyn_cast() const {
    141       if (is<T>()) return get<T>();
    142       return T();
    143     }
    144 
    145     /// \brief If the union is set to the first pointer type get an address
    146     /// pointing to it.
    147     PT1 const *getAddrOfPtr1() const {
    148       return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
    149     }
    150 
    151     /// \brief If the union is set to the first pointer type get an address
    152     /// pointing to it.
    153     PT1 *getAddrOfPtr1() {
    154       assert(is<PT1>() && "Val is not the first pointer");
    155       assert(get<PT1>() == Val.getPointer() &&
    156          "Can't get the address because PointerLikeTypeTraits changes the ptr");
    157       return (PT1 *)Val.getAddrOfPointer();
    158     }
    159 
    160     /// Assignment operators - Allow assigning into this union from either
    161     /// pointer type, setting the discriminator to remember what it came from.
    162     const PointerUnion &operator=(const PT1 &RHS) {
    163       Val.setPointer(
    164          const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS)));
    165       Val.setInt(0);
    166       return *this;
    167     }
    168     const PointerUnion &operator=(const PT2 &RHS) {
    169       Val.setPointer(
    170         const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)));
    171       Val.setInt(1);
    172       return *this;
    173     }
    174 
    175     void *getOpaqueValue() const { return Val.getOpaqueValue(); }
    176     static inline PointerUnion getFromOpaqueValue(void *VP) {
    177       PointerUnion V;
    178       V.Val = ValTy::getFromOpaqueValue(VP);
    179       return V;
    180     }
    181   };
    182 
    183   // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
    184   // # low bits available = min(PT1bits,PT2bits)-1.
    185   template<typename PT1, typename PT2>
    186   class PointerLikeTypeTraits<PointerUnion<PT1, PT2> > {
    187   public:
    188     static inline void *
    189     getAsVoidPointer(const PointerUnion<PT1, PT2> &P) {
    190       return P.getOpaqueValue();
    191     }
    192     static inline PointerUnion<PT1, PT2>
    193     getFromVoidPointer(void *P) {
    194       return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
    195     }
    196 
    197     // The number of bits available are the min of the two pointer types.
    198     enum {
    199       NumLowBitsAvailable =
    200         PointerLikeTypeTraits<typename PointerUnion<PT1,PT2>::ValTy>
    201           ::NumLowBitsAvailable
    202     };
    203   };
    204 
    205 
    206   /// PointerUnion3 - This is a pointer union of three pointer types.  See
    207   /// documentation for PointerUnion for usage.
    208   template <typename PT1, typename PT2, typename PT3>
    209   class PointerUnion3 {
    210   public:
    211     typedef PointerUnion<PT1, PT2> InnerUnion;
    212     typedef PointerUnion<InnerUnion, PT3> ValTy;
    213   private:
    214     ValTy Val;
    215 
    216     struct IsInnerUnion {
    217       ValTy Val;
    218       IsInnerUnion(ValTy val) : Val(val) { }
    219       template<typename T>
    220       int is() const {
    221         return Val.template is<InnerUnion>() &&
    222                Val.template get<InnerUnion>().template is<T>();
    223       }
    224       template<typename T>
    225       T get() const {
    226         return Val.template get<InnerUnion>().template get<T>();
    227       }
    228     };
    229 
    230     struct IsPT3 {
    231       ValTy Val;
    232       IsPT3(ValTy val) : Val(val) { }
    233       template<typename T>
    234       int is() const {
    235         return Val.template is<T>();
    236       }
    237       template<typename T>
    238       T get() const {
    239         return Val.template get<T>();
    240       }
    241     };
    242 
    243   public:
    244     PointerUnion3() {}
    245 
    246     PointerUnion3(PT1 V) {
    247       Val = InnerUnion(V);
    248     }
    249     PointerUnion3(PT2 V) {
    250       Val = InnerUnion(V);
    251     }
    252     PointerUnion3(PT3 V) {
    253       Val = V;
    254     }
    255 
    256     /// isNull - Return true if the pointer held in the union is null,
    257     /// regardless of which type it is.
    258     bool isNull() const { return Val.isNull(); }
    259     operator bool() const { return !isNull(); }
    260 
    261     /// is<T>() return true if the Union currently holds the type matching T.
    262     template<typename T>
    263     int is() const {
    264       // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
    265       typedef typename
    266         ::llvm::PointerUnionTypeSelector<PT1, T, IsInnerUnion,
    267           ::llvm::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3 >
    268                                                                    >::Return Ty;
    269       return Ty(Val).template is<T>();
    270     }
    271 
    272     /// get<T>() - Return the value of the specified pointer type. If the
    273     /// specified pointer type is incorrect, assert.
    274     template<typename T>
    275     T get() const {
    276       assert(is<T>() && "Invalid accessor called");
    277       // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
    278       typedef typename
    279         ::llvm::PointerUnionTypeSelector<PT1, T, IsInnerUnion,
    280           ::llvm::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3 >
    281                                                                    >::Return Ty;
    282       return Ty(Val).template get<T>();
    283     }
    284 
    285     /// dyn_cast<T>() - If the current value is of the specified pointer type,
    286     /// return it, otherwise return null.
    287     template<typename T>
    288     T dyn_cast() const {
    289       if (is<T>()) return get<T>();
    290       return T();
    291     }
    292 
    293     /// Assignment operators - Allow assigning into this union from either
    294     /// pointer type, setting the discriminator to remember what it came from.
    295     const PointerUnion3 &operator=(const PT1 &RHS) {
    296       Val = InnerUnion(RHS);
    297       return *this;
    298     }
    299     const PointerUnion3 &operator=(const PT2 &RHS) {
    300       Val = InnerUnion(RHS);
    301       return *this;
    302     }
    303     const PointerUnion3 &operator=(const PT3 &RHS) {
    304       Val = RHS;
    305       return *this;
    306     }
    307 
    308     void *getOpaqueValue() const { return Val.getOpaqueValue(); }
    309     static inline PointerUnion3 getFromOpaqueValue(void *VP) {
    310       PointerUnion3 V;
    311       V.Val = ValTy::getFromOpaqueValue(VP);
    312       return V;
    313     }
    314   };
    315 
    316   // Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
    317   // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
    318   template<typename PT1, typename PT2, typename PT3>
    319   class PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3> > {
    320   public:
    321     static inline void *
    322     getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) {
    323       return P.getOpaqueValue();
    324     }
    325     static inline PointerUnion3<PT1, PT2, PT3>
    326     getFromVoidPointer(void *P) {
    327       return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
    328     }
    329 
    330     // The number of bits available are the min of the two pointer types.
    331     enum {
    332       NumLowBitsAvailable =
    333         PointerLikeTypeTraits<typename PointerUnion3<PT1, PT2, PT3>::ValTy>
    334           ::NumLowBitsAvailable
    335     };
    336   };
    337 
    338   /// PointerUnion4 - This is a pointer union of four pointer types.  See
    339   /// documentation for PointerUnion for usage.
    340   template <typename PT1, typename PT2, typename PT3, typename PT4>
    341   class PointerUnion4 {
    342   public:
    343     typedef PointerUnion<PT1, PT2> InnerUnion1;
    344     typedef PointerUnion<PT3, PT4> InnerUnion2;
    345     typedef PointerUnion<InnerUnion1, InnerUnion2> ValTy;
    346   private:
    347     ValTy Val;
    348   public:
    349     PointerUnion4() {}
    350 
    351     PointerUnion4(PT1 V) {
    352       Val = InnerUnion1(V);
    353     }
    354     PointerUnion4(PT2 V) {
    355       Val = InnerUnion1(V);
    356     }
    357     PointerUnion4(PT3 V) {
    358       Val = InnerUnion2(V);
    359     }
    360     PointerUnion4(PT4 V) {
    361       Val = InnerUnion2(V);
    362     }
    363 
    364     /// isNull - Return true if the pointer held in the union is null,
    365     /// regardless of which type it is.
    366     bool isNull() const { return Val.isNull(); }
    367     operator bool() const { return !isNull(); }
    368 
    369     /// is<T>() return true if the Union currently holds the type matching T.
    370     template<typename T>
    371     int is() const {
    372       // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
    373       typedef typename
    374         ::llvm::PointerUnionTypeSelector<PT1, T, InnerUnion1,
    375           ::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1, InnerUnion2 >
    376                                                                    >::Return Ty;
    377       return Val.template is<Ty>() &&
    378              Val.template get<Ty>().template is<T>();
    379     }
    380 
    381     /// get<T>() - Return the value of the specified pointer type. If the
    382     /// specified pointer type is incorrect, assert.
    383     template<typename T>
    384     T get() const {
    385       assert(is<T>() && "Invalid accessor called");
    386       // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
    387       typedef typename
    388         ::llvm::PointerUnionTypeSelector<PT1, T, InnerUnion1,
    389           ::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1, InnerUnion2 >
    390                                                                    >::Return Ty;
    391       return Val.template get<Ty>().template get<T>();
    392     }
    393 
    394     /// dyn_cast<T>() - If the current value is of the specified pointer type,
    395     /// return it, otherwise return null.
    396     template<typename T>
    397     T dyn_cast() const {
    398       if (is<T>()) return get<T>();
    399       return T();
    400     }
    401 
    402     /// Assignment operators - Allow assigning into this union from either
    403     /// pointer type, setting the discriminator to remember what it came from.
    404     const PointerUnion4 &operator=(const PT1 &RHS) {
    405       Val = InnerUnion1(RHS);
    406       return *this;
    407     }
    408     const PointerUnion4 &operator=(const PT2 &RHS) {
    409       Val = InnerUnion1(RHS);
    410       return *this;
    411     }
    412     const PointerUnion4 &operator=(const PT3 &RHS) {
    413       Val = InnerUnion2(RHS);
    414       return *this;
    415     }
    416     const PointerUnion4 &operator=(const PT4 &RHS) {
    417       Val = InnerUnion2(RHS);
    418       return *this;
    419     }
    420 
    421     void *getOpaqueValue() const { return Val.getOpaqueValue(); }
    422     static inline PointerUnion4 getFromOpaqueValue(void *VP) {
    423       PointerUnion4 V;
    424       V.Val = ValTy::getFromOpaqueValue(VP);
    425       return V;
    426     }
    427   };
    428 
    429   // Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has
    430   // # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
    431   template<typename PT1, typename PT2, typename PT3, typename PT4>
    432   class PointerLikeTypeTraits<PointerUnion4<PT1, PT2, PT3, PT4> > {
    433   public:
    434     static inline void *
    435     getAsVoidPointer(const PointerUnion4<PT1, PT2, PT3, PT4> &P) {
    436       return P.getOpaqueValue();
    437     }
    438     static inline PointerUnion4<PT1, PT2, PT3, PT4>
    439     getFromVoidPointer(void *P) {
    440       return PointerUnion4<PT1, PT2, PT3, PT4>::getFromOpaqueValue(P);
    441     }
    442 
    443     // The number of bits available are the min of the two pointer types.
    444     enum {
    445       NumLowBitsAvailable =
    446         PointerLikeTypeTraits<typename PointerUnion4<PT1, PT2, PT3, PT4>::ValTy>
    447           ::NumLowBitsAvailable
    448     };
    449   };
    450 }
    451 
    452 #endif
    453