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