PointerUnion.h revision e8bc475668ddd2f31f44dd00b042d15b255e1b9e
1402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===// 2402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// 3402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// The LLVM Compiler Infrastructure 4402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// 5402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// This file is distributed under the University of Illinois Open Source 6402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// License. See LICENSE.TXT for details. 7402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// 8402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll//===----------------------------------------------------------------------===// 9402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// 10402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// This file defines the PointerUnion class, which is a discriminated union of 11402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// pointer types. 12402794e73aed8611d62eb4b01cd155e2d76fcb87Raphael Moll// 13//===----------------------------------------------------------------------===// 14 15#ifndef LLVM_ADT_POINTERUNION_H 16#define LLVM_ADT_POINTERUNION_H 17 18#include "llvm/ADT/PointerIntPair.h" 19 20namespace llvm { 21 22 /// getPointerUnionTypeNum - If the argument has type PT1* or PT2* return 23 /// false or true respectively. 24 template <typename PT1, typename PT2> 25 static inline int getPointerUnionTypeNum(PT1 *P) { return 0; } 26 template <typename PT1, typename PT2> 27 static inline int getPointerUnionTypeNum(PT2 *P) { return 1; } 28 template <typename PT1, typename PT2> 29 static inline int getPointerUnionTypeNum(...) { return -1; } 30 31 32 /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion 33 /// for the two template arguments. 34 template <typename PT1, typename PT2> 35 class PointerUnionUIntTraits { 36 public: 37 static inline void *getAsVoidPointer(void *P) { return P; } 38 static inline void *getFromVoidPointer(void *P) { return P; } 39 enum { 40 PT1BitsAv = PointerLikeTypeTraits<PT1>::NumLowBitsAvailable, 41 PT2BitsAv = PointerLikeTypeTraits<PT2>::NumLowBitsAvailable, 42 NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv 43 }; 44 }; 45 46 /// PointerUnion - This implements a discriminated union of two pointer types, 47 /// and keeps the discriminator bit-mangled into the low bits of the pointer. 48 /// This allows the implementation to be extremely efficient in space, but 49 /// permits a very natural and type-safe API. 50 /// 51 /// Common use patterns would be something like this: 52 /// PointerUnion<int*, float*> P; 53 /// P = (int*)0; 54 /// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0" 55 /// X = P.get<int*>(); // ok. 56 /// Y = P.get<float*>(); // runtime assertion failure. 57 /// Z = P.get<double*>(); // does not compile. 58 /// P = (float*)0; 59 /// Y = P.get<float*>(); // ok. 60 /// X = P.get<int*>(); // runtime assertion failure. 61 template <typename PT1, typename PT2> 62 class PointerUnion { 63 public: 64 typedef PointerIntPair<void*, 1, bool, 65 PointerUnionUIntTraits<PT1,PT2> > ValTy; 66 private: 67 ValTy Val; 68 public: 69 PointerUnion() {} 70 71 PointerUnion(PT1 V) { 72 Val.setPointer(PointerLikeTypeTraits<PT1>::getAsVoidPointer(V)); 73 Val.setInt(0); 74 } 75 PointerUnion(PT2 V) { 76 Val.setPointer(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)); 77 Val.setInt(1); 78 } 79 80 /// isNull - Return true if the pointer help in the union is null, 81 /// regardless of which type it is. 82 bool isNull() const { return Val.getPointer() == 0; } 83 operator bool() const { return !isNull(); } 84 85 /// is<T>() return true if the Union currently holds the type matching T. 86 template<typename T> 87 int is() const { 88 int TyNo = ::llvm::getPointerUnionTypeNum<PT1, PT2>((T*)0); 89 assert(TyNo != -1 && "Type query could never succeed on PointerUnion!"); 90 return Val.getInt() == TyNo; 91 } 92 93 /// get<T>() - Return the value of the specified pointer type. If the 94 /// specified pointer type is incorrect, assert. 95 template<typename T> 96 T get() const { 97 assert(is<T>() && "Invalid accessor called"); 98 return PointerLikeTypeTraits<T>::getFromVoidPointer(Val.getPointer()); 99 } 100 101 /// dyn_cast<T>() - If the current value is of the specified pointer type, 102 /// return it, otherwise return null. 103 template<typename T> 104 T dyn_cast() const { 105 if (is<T>()) return get<T>(); 106 return T(); 107 } 108 109 /// Assignment operators - Allow assigning into this union from either 110 /// pointer type, setting the discriminator to remember what it came from. 111 const PointerUnion &operator=(const PT1 &RHS) { 112 Val.setPointer(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS)); 113 Val.setInt(0); 114 return *this; 115 } 116 const PointerUnion &operator=(const PT2 &RHS) { 117 Val.setPointer(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)); 118 Val.setInt(1); 119 return *this; 120 } 121 122 void *getOpaqueValue() const { return Val.getOpaqueValue(); } 123 static PointerUnion getFromOpaqueValue(void *VP) { 124 PointerUnion V; 125 V.Val = ValTy::getFromOpaqueValue(VP); 126 return V; 127 } 128 }; 129 130 // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has 131 // # low bits available = min(PT1bits,PT2bits)-1. 132 template<typename PT1, typename PT2> 133 class PointerLikeTypeTraits<PointerUnion<PT1, PT2> > { 134 public: 135 static inline void * 136 getAsVoidPointer(const PointerUnion<PT1, PT2> &P) { 137 return P.getOpaqueValue(); 138 } 139 static inline PointerUnion<PT1, PT2> 140 getFromVoidPointer(void *P) { 141 return PointerUnion<PT1, PT2>::getFromOpaqueValue(P); 142 } 143 144 // The number of bits available are the min of the two pointer types. 145 enum { 146 NumLowBitsAvailable = 147 PointerLikeTypeTraits<typename PointerUnion<PT1,PT2>::ValTy> 148 ::NumLowBitsAvailable 149 }; 150 }; 151 152 153 /// PointerUnion3 - This is a pointer union of three pointer types. See 154 /// documentation for PointerUnion for usage. 155 template <typename PT1, typename PT2, typename PT3> 156 class PointerUnion3 { 157 public: 158 typedef PointerUnion<PT1, PT2> InnerUnion; 159 typedef PointerUnion<InnerUnion, PT3> ValTy; 160 private: 161 ValTy Val; 162 public: 163 PointerUnion3() {} 164 165 PointerUnion3(PT1 V) { 166 Val = InnerUnion(V); 167 } 168 PointerUnion3(PT2 V) { 169 Val = InnerUnion(V); 170 } 171 PointerUnion3(PT3 V) { 172 Val = V; 173 } 174 175 /// isNull - Return true if the pointer help in the union is null, 176 /// regardless of which type it is. 177 bool isNull() const { return Val.isNull(); } 178 operator bool() const { return !isNull(); } 179 180 /// is<T>() return true if the Union currently holds the type matching T. 181 template<typename T> 182 int is() const { 183 // Is it PT1/PT2? 184 if (::llvm::getPointerUnionTypeNum<PT1, PT2>((T*)0) != -1) 185 return Val.get<InnerUnion>().is<T>(); 186 // Must be PT3 or statically invalid. 187 assert(Val.is<T>()); 188 return true; 189 } 190 191 /// get<T>() - Return the value of the specified pointer type. If the 192 /// specified pointer type is incorrect, assert. 193 template<typename T> 194 T get() const { 195 assert(is<T>() && "Invalid accessor called"); 196 if (Val.is<T>()) 197 return Val.get<T>(); 198 return Val.get<InnerUnion>().get<T>(); 199 } 200 201 /// dyn_cast<T>() - If the current value is of the specified pointer type, 202 /// return it, otherwise return null. 203 template<typename T> 204 T dyn_cast() const { 205 if (is<T>()) return get<T>(); 206 return T(); 207 } 208 209 /// Assignment operators - Allow assigning into this union from either 210 /// pointer type, setting the discriminator to remember what it came from. 211 const PointerUnion3 &operator=(const PT1 &RHS) { 212 Val = InnerUnion(RHS); 213 return *this; 214 } 215 const PointerUnion3 &operator=(const PT2 &RHS) { 216 Val = InnerUnion(RHS); 217 return *this; 218 } 219 const PointerUnion3 &operator=(const PT3 &RHS) { 220 Val = RHS; 221 return *this; 222 } 223 224 void *getOpaqueValue() const { return Val.getOpaqueValue(); } 225 static PointerUnion3 getFromOpaqueValue(void *VP) { 226 PointerUnion3 V; 227 V.Val = ValTy::getFromOpaqueValue(VP); 228 return V; 229 } 230 }; 231 232 // Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has 233 // # low bits available = min(PT1bits,PT2bits,PT2bits)-2. 234 template<typename PT1, typename PT2, typename PT3> 235 class PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3> > { 236 public: 237 static inline void * 238 getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) { 239 return P.getOpaqueValue(); 240 } 241 static inline PointerUnion3<PT1, PT2, PT3> 242 getFromVoidPointer(void *P) { 243 return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P); 244 } 245 246 // The number of bits available are the min of the two pointer types. 247 enum { 248 NumLowBitsAvailable = 249 PointerLikeTypeTraits<typename PointerUnion3<PT1, PT2, PT3>::ValTy> 250 ::NumLowBitsAvailable 251 }; 252 }; 253} 254 255#endif 256