X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FSupport%2FCasting.h;h=720c34f7b4913103452da1414f0eaa3e0a2d2dea;hb=bef2236283c333f17613b2ea4904878228fedb6e;hp=e59b7c2d07681611d2138455c0423f8079a05032;hpb=589df88ba03a81b2b3dc9d084c191a3a74724ecd;p=oota-llvm.git diff --git a/include/llvm/Support/Casting.h b/include/llvm/Support/Casting.h index e59b7c2d076..720c34f7b49 100644 --- a/include/llvm/Support/Casting.h +++ b/include/llvm/Support/Casting.h @@ -1,58 +1,256 @@ -//===-- Support/Casting.h - Allow flexible, checked, casts -------*- C++ -*--=// +//===-- llvm/Support/Casting.h - Allow flexible, checked, casts -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// // // This file defines the isa(), cast(), dyn_cast(), cast_or_null(), // and dyn_cast_or_null() templates. // //===----------------------------------------------------------------------===// -#ifndef SUPPORT_CASTING_H -#define SUPPORT_CASTING_H +#ifndef LLVM_SUPPORT_CASTING_H +#define LLVM_SUPPORT_CASTING_H -// real_type - Provide a macro to get the real type of a value that might be -// a use. This provides a typedef 'Type' that is the argument type for all -// non UseTy types, and is the contained pointer type of the use if it is a -// UseTy. -// -template class real_type { typedef X Type; }; +#include "llvm/Support/Compiler.h" +#include "llvm/Support/type_traits.h" +#include + +namespace llvm { //===----------------------------------------------------------------------===// -// Type Checking Templates +// isa Support Templates //===----------------------------------------------------------------------===// +// Define a template that can be specialized by smart pointers to reflect the +// fact that they are automatically dereferenced, and are not involved with the +// template selection process... the default implementation is a noop. +// +template struct simplify_type { + typedef From SimpleType; // The real type this represents... + + // An accessor to get the real value... + static SimpleType &getSimplifiedValue(From &Val) { return Val; } +}; + +template struct simplify_type { + typedef typename simplify_type::SimpleType NonConstSimpleType; + typedef typename add_const_past_pointer::type + SimpleType; + typedef typename add_lvalue_reference_if_not_pointer::type + RetType; + static RetType getSimplifiedValue(const From& Val) { + return simplify_type::getSimplifiedValue(const_cast(Val)); + } +}; + +// The core of the implementation of isa is here; To and From should be +// the names of classes. This template can be specialized to customize the +// implementation of isa<> without rewriting it from scratch. +template +struct isa_impl { + static inline bool doit(const From &Val) { + return To::classof(&Val); + } +}; + +/// \brief Always allow upcasts, and perform no dynamic check for them. +template +struct isa_impl + >::type + > { + static inline bool doit(const From &) { return true; } +}; + +template struct isa_impl_cl { + static inline bool doit(const From &Val) { + return isa_impl::doit(Val); + } +}; + +template struct isa_impl_cl { + static inline bool doit(const From &Val) { + return isa_impl::doit(Val); + } +}; + +template struct isa_impl_cl { + static inline bool doit(const From *Val) { + assert(Val && "isa<> used on a null pointer"); + return isa_impl::doit(*Val); + } +}; + +template struct isa_impl_cl { + static inline bool doit(const From *Val) { + assert(Val && "isa<> used on a null pointer"); + return isa_impl::doit(*Val); + } +}; + +template struct isa_impl_cl { + static inline bool doit(const From *Val) { + assert(Val && "isa<> used on a null pointer"); + return isa_impl::doit(*Val); + } +}; + +template struct isa_impl_cl { + static inline bool doit(const From *Val) { + assert(Val && "isa<> used on a null pointer"); + return isa_impl::doit(*Val); + } +}; + +template +struct isa_impl_wrap { + // When From != SimplifiedType, we can simplify the type some more by using + // the simplify_type template. + static bool doit(const From &Val) { + return isa_impl_wrap::SimpleType>::doit( + simplify_type::getSimplifiedValue(Val)); + } +}; + +template +struct isa_impl_wrap { + // When From == SimpleType, we are as simple as we are going to get. + static bool doit(const FromTy &Val) { + return isa_impl_cl::doit(Val); + } +}; + // isa - Return true if the parameter to the template is an instance of the // template type argument. Used like this: // // if (isa(myVal)) { ... } // template -inline bool isa(Y Val) { - assert(Val && "isa(NULL) invoked!"); - return X::classof(Val); +LLVM_ATTRIBUTE_UNUSED_RESULT inline bool isa(const Y &Val) { + return isa_impl_wrap::SimpleType>::doit(Val); } +//===----------------------------------------------------------------------===// +// cast Support Templates +//===----------------------------------------------------------------------===// + +template struct cast_retty; + + +// Calculate what type the 'cast' function should return, based on a requested +// type of To and a source type of From. +template struct cast_retty_impl { + typedef To& ret_type; // Normal case, return Ty& +}; +template struct cast_retty_impl { + typedef const To &ret_type; // Normal case, return Ty& +}; + +template struct cast_retty_impl { + typedef To* ret_type; // Pointer arg case, return Ty* +}; + +template struct cast_retty_impl { + typedef const To* ret_type; // Constant pointer arg case, return const Ty* +}; + +template struct cast_retty_impl { + typedef const To* ret_type; // Constant pointer arg case, return const Ty* +}; + + +template +struct cast_retty_wrap { + // When the simplified type and the from type are not the same, use the type + // simplifier to reduce the type, then reuse cast_retty_impl to get the + // resultant type. + typedef typename cast_retty::ret_type ret_type; +}; + +template +struct cast_retty_wrap { + // When the simplified type is equal to the from type, use it directly. + typedef typename cast_retty_impl::ret_type ret_type; +}; + +template +struct cast_retty { + typedef typename cast_retty_wrap::SimpleType>::ret_type ret_type; +}; + +// Ensure the non-simple values are converted using the simplify_type template +// that may be specialized by smart pointers... +// +template struct cast_convert_val { + // This is not a simple type, use the template to simplify it... + static typename cast_retty::ret_type doit(From &Val) { + return cast_convert_val::SimpleType>::doit( + simplify_type::getSimplifiedValue(Val)); + } +}; + +template struct cast_convert_val { + // This _is_ a simple type, just cast it. + static typename cast_retty::ret_type doit(const FromTy &Val) { + typename cast_retty::ret_type Res2 + = (typename cast_retty::ret_type)const_cast(Val); + return Res2; + } +}; + +template struct is_simple_type { + static const bool value = + is_same::SimpleType>::value; +}; // cast - Return the argument parameter cast to the specified type. This // casting operator asserts that the type is correct, so it does not return null -// on failure. But it will correctly return NULL when the input is NULL. -// Used Like this: +// on failure. It does not allow a null argument (use cast_or_null for that). +// It is typically used like this: // -// cast< Instruction>(myVal)->getParent() -// cast(myVal)->getParent() +// cast(myVal)->getParent() // template -inline X *cast(Y Val) { - assert(isa(Val) && "cast() argument of uncompatible type!"); - return (X*)(real_type::Type)Val; +inline typename enable_if_c::value, + typename cast_retty::ret_type>::type +cast(const Y &Val) { + assert(isa(Val) && "cast() argument of incompatible type!"); + return cast_convert_val< + X, const Y, typename simplify_type::SimpleType>::doit(Val); +} + +template +inline typename cast_retty::ret_type cast(Y &Val) { + assert(isa(Val) && "cast() argument of incompatible type!"); + return cast_convert_val::SimpleType>::doit(Val); +} + +template +inline typename cast_retty::ret_type cast(Y *Val) { + assert(isa(Val) && "cast() argument of incompatible type!"); + return cast_convert_val::SimpleType>::doit(Val); } // cast_or_null - Functionally identical to cast, except that a null value is // accepted. // template -inline X *cast_or_null(Y Val) { - assert((Val == 0 || isa(Val)) && - "cast_or_null() argument of uncompatible type!"); - return (X*)(real_type::Type)Val; +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty::ret_type +cast_or_null(Y *Val) { + if (Val == 0) return 0; + assert(isa(Val) && "cast_or_null() argument of incompatible type!"); + return cast(Val); } @@ -61,11 +259,25 @@ inline X *cast_or_null(Y Val) { // be used to test for a type as well as cast if successful. This should be // used in the context of an if statement like this: // -// if (const Instruction *I = dyn_cast(myVal)) { ... } +// if (const Instruction *I = dyn_cast(myVal)) { ... } // template -inline X *dyn_cast(Y Val) { +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename enable_if_c< + !is_simple_type::value, typename cast_retty::ret_type>::type +dyn_cast(const Y &Val) { + return isa(Val) ? cast(Val) : 0; +} + +template +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty::ret_type +dyn_cast(Y &Val) { + return isa(Val) ? cast(Val) : 0; +} + +template +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty::ret_type +dyn_cast(Y *Val) { return isa(Val) ? cast(Val) : 0; } @@ -73,8 +285,11 @@ inline X *dyn_cast(Y Val) { // value is accepted. // template -inline X *dyn_cast_or_null(Y Val) { +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty::ret_type +dyn_cast_or_null(Y *Val) { return (Val && isa(Val)) ? cast(Val) : 0; } +} // End llvm namespace + #endif