Casting.h revision 776f776838d6e2f83d899bc99452dc83779c341b
1//===-- Support/Casting.h - Allow flexible, checked, casts -------*- C++ -*--=// 2// 3// This file defines the isa<X>(), cast<X>(), dyn_cast<X>(), cast_or_null<X>(), 4// and dyn_cast_or_null<X>() templates. 5// 6//===----------------------------------------------------------------------===// 7 8#ifndef SUPPORT_CASTING_H 9#define SUPPORT_CASTING_H 10 11//===----------------------------------------------------------------------===// 12// isa<x> Support Templates 13//===----------------------------------------------------------------------===// 14 15template<typename FromCl> struct isa_impl_cl; 16 17// Define a template that can be specialized by smart pointers to reflect the 18// fact that they are automatically dereferenced, and are not involved with the 19// template selection process... the default implementation is a noop. 20// 21template<typename From> struct simplify_type { 22 typedef From SimpleType; // The real type this represents... 23 24 // An accessor to get the real value... 25 static SimpleType &getSimplifiedValue(From &Val) { return Val; } 26}; 27 28template<typename From> struct simplify_type<const From> { 29 typedef const From SimpleType; 30 static SimpleType &getSimplifiedValue(const From &Val) { 31 return simplify_type<From>::getSimplifiedValue((From&)Val); 32 } 33}; 34 35 36// isa<X> - Return true if the parameter to the template is an instance of the 37// template type argument. Used like this: 38// 39// if (isa<Type*>(myVal)) { ... } 40// 41template <typename To, typename From> 42inline bool isa_impl(const From &Val) { 43 return To::classof(&Val); 44} 45 46template<typename To, typename From, typename SimpleType> 47struct isa_impl_wrap { 48 // When From != SimplifiedType, we can simplify the type some more by using 49 // the simplify_type template. 50 static bool doit(const From &Val) { 51 return isa_impl_cl<const SimpleType>::template 52 isa<To>(simplify_type<const From>::getSimplifiedValue(Val)); 53 } 54}; 55 56template<typename To, typename FromTy> 57struct isa_impl_wrap<To, const FromTy, const FromTy> { 58 // When From == SimpleType, we are as simple as we are going to get. 59 static bool doit(const FromTy &Val) { 60 return isa_impl<To,FromTy>(Val); 61 } 62}; 63 64// isa_impl_cl - Use class partial specialization to transform types to a single 65// canonical form for isa_impl. 66// 67template<typename FromCl> 68struct isa_impl_cl { 69 template<class ToCl> 70 static bool isa(const FromCl &Val) { 71 return isa_impl_wrap<ToCl,const FromCl, 72 typename simplify_type<const FromCl>::SimpleType>::doit(Val); 73 } 74}; 75 76// Specialization used to strip const qualifiers off of the FromCl type... 77template<typename FromCl> 78struct isa_impl_cl<const FromCl> { 79 template<class ToCl> 80 static bool isa(const FromCl &Val) { 81 return isa_impl_cl<FromCl>::template isa<ToCl>(Val); 82 } 83}; 84 85// Define pointer traits in terms of base traits... 86template<class FromCl> 87struct isa_impl_cl<FromCl*> { 88 template<class ToCl> 89 static bool isa(FromCl *Val) { 90 return isa_impl_cl<FromCl>::template isa<ToCl>(*Val); 91 } 92}; 93 94// Define reference traits in terms of base traits... 95template<class FromCl> 96struct isa_impl_cl<FromCl&> { 97 template<class ToCl> 98 static bool isa(FromCl &Val) { 99 return isa_impl_cl<FromCl>::template isa<ToCl>(&Val); 100 } 101}; 102 103template <class X, class Y> 104inline bool isa(const Y &Val) { 105 return isa_impl_cl<Y>::template isa<X>(Val); 106} 107 108//===----------------------------------------------------------------------===// 109// cast<x> Support Templates 110//===----------------------------------------------------------------------===// 111 112template<class To, class From> struct cast_retty; 113 114 115// Calculate what type the 'cast' function should return, based on a requested 116// type of To and a source type of From. 117template<class To, class From> struct cast_retty_impl { 118 typedef To& ret_type; // Normal case, return Ty& 119}; 120template<class To, class From> struct cast_retty_impl<To, const From> { 121 typedef const To &ret_type; // Normal case, return Ty& 122}; 123 124template<class To, class From> struct cast_retty_impl<To, From*> { 125 typedef To* ret_type; // Pointer arg case, return Ty* 126}; 127 128template<class To, class From> struct cast_retty_impl<To, const From*> { 129 typedef const To* ret_type; // Constant pointer arg case, return const Ty* 130}; 131 132template<class To, class From> struct cast_retty_impl<To, const From*const> { 133 typedef const To* ret_type; // Constant pointer arg case, return const Ty* 134}; 135 136 137template<class To, class From, class SimpleFrom> 138struct cast_retty_wrap { 139 // When the simplified type and the from type are not the same, use the type 140 // simplifier to reduce the type, then reuse cast_retty_impl to get the 141 // resultant type. 142 typedef typename cast_retty<To, SimpleFrom>::ret_type ret_type; 143}; 144 145template<class To, class FromTy> 146struct cast_retty_wrap<To, FromTy, FromTy> { 147 // When the simplified type is equal to the from type, use it directly. 148 typedef typename cast_retty_impl<To,FromTy>::ret_type ret_type; 149}; 150 151template<class To, class From> 152struct cast_retty { 153 typedef typename cast_retty_wrap<To, From, 154 typename simplify_type<From>::SimpleType>::ret_type ret_type; 155}; 156 157// Ensure the non-simple values are converted using the simplify_type template 158// that may be specialized by smart pointers... 159// 160template<class To, class From, class SimpleFrom> struct cast_convert_val { 161 // This is not a simple type, use the template to simplify it... 162 static typename cast_retty<To, From>::ret_type doit(const From &Val) { 163 return cast_convert_val<To, SimpleFrom, 164 typename simplify_type<SimpleFrom>::SimpleType>::doit( 165 simplify_type<From>::getSimplifiedValue(Val)); 166 } 167}; 168 169template<class To, class FromTy> struct cast_convert_val<To,FromTy,FromTy> { 170 // This _is_ a simple type, just cast it. 171 static typename cast_retty<To, FromTy>::ret_type doit(const FromTy &Val) { 172 return (typename cast_retty<To, FromTy>::ret_type)Val; 173 } 174}; 175 176 177 178// cast<X> - Return the argument parameter cast to the specified type. This 179// casting operator asserts that the type is correct, so it does not return null 180// on failure. But it will correctly return NULL when the input is NULL. 181// Used Like this: 182// 183// cast<Instruction>(myVal)->getParent() 184// 185template <class X, class Y> 186inline typename cast_retty<X, Y>::ret_type cast(const Y &Val) { 187 assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!"); 188 return cast_convert_val<X, Y, 189 typename simplify_type<Y>::SimpleType>::doit(Val); 190} 191 192// cast_or_null<X> - Functionally identical to cast, except that a null value is 193// accepted. 194// 195template <class X, class Y> 196inline typename cast_retty<X, Y*>::ret_type cast_or_null(Y *Val) { 197 if (Val == 0) return 0; 198 assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!"); 199 return cast<X>(Val); 200} 201 202 203// dyn_cast<X> - Return the argument parameter cast to the specified type. This 204// casting operator returns null if the argument is of the wrong type, so it can 205// be used to test for a type as well as cast if successful. This should be 206// used in the context of an if statement like this: 207// 208// if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... } 209// 210 211template <class X, class Y> 212inline typename cast_retty<X, Y>::ret_type dyn_cast(Y Val) { 213 return isa<X>(Val) ? cast<X, Y>(Val) : 0; 214} 215 216// dyn_cast_or_null<X> - Functionally identical to dyn_cast, except that a null 217// value is accepted. 218// 219template <class X, class Y> 220inline typename cast_retty<X, Y>::ret_type dyn_cast_or_null(Y Val) { 221 return (Val && isa<X>(Val)) ? cast<X, Y>(Val) : 0; 222} 223 224 225#ifdef DEBUG_CAST_OPERATORS 226#include <iostream> 227 228struct bar { 229 bar() {} 230private: 231 bar(const bar &); 232}; 233struct foo { 234 void ext() const; 235 /* static bool classof(const bar *X) { 236 cerr << "Classof: " << X << "\n"; 237 return true; 238 }*/ 239}; 240 241template <> inline bool isa_impl<foo,bar>(const bar &Val) { 242 cerr << "Classof: " << &Val << "\n"; 243 return true; 244} 245 246 247bar *fub(); 248void test(bar &B1, const bar *B2) { 249 // test various configurations of const 250 const bar &B3 = B1; 251 const bar *const B4 = B2; 252 253 // test isa 254 if (!isa<foo>(B1)) return; 255 if (!isa<foo>(B2)) return; 256 if (!isa<foo>(B3)) return; 257 if (!isa<foo>(B4)) return; 258 259 // test cast 260 foo &F1 = cast<foo>(B1); 261 const foo *F3 = cast<foo>(B2); 262 const foo *F4 = cast<foo>(B2); 263 const foo &F8 = cast<foo>(B3); 264 const foo *F9 = cast<foo>(B4); 265 foo *F10 = cast<foo>(fub()); 266 267 // test cast_or_null 268 const foo *F11 = cast_or_null<foo>(B2); 269 const foo *F12 = cast_or_null<foo>(B2); 270 const foo *F13 = cast_or_null<foo>(B4); 271 const foo *F14 = cast_or_null<foo>(fub()); // Shouldn't print. 272 273 // These lines are errors... 274 //foo *F20 = cast<foo>(B2); // Yields const foo* 275 //foo &F21 = cast<foo>(B3); // Yields const foo& 276 //foo *F22 = cast<foo>(B4); // Yields const foo* 277 //foo &F23 = cast_or_null<foo>(B1); 278 //const foo &F24 = cast_or_null<foo>(B3); 279} 280 281bar *fub() { return 0; } 282void main() { 283 bar B; 284 test(B, &B); 285} 286 287#endif 288 289#endif 290