1 /* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #ifndef FOUNDATION_APPEXECFWK_STANDARD_TOOLS_CHECKED_CAST_H 16 #define FOUNDATION_APPEXECFWK_STANDARD_TOOLS_CHECKED_CAST_H 17 18 #include <exception> 19 #include <typeinfo> 20 #include <cassert> 21 #include "app_log_wrapper.h" 22 23 namespace hidden { 24 // workaroud for T& equally matching f(T&) and f(T const&) 25 // so we do the following: T const& never matches f(T&), therefore: 26 // f(T&, LookUpHelper2 const&) and f(T const&, LookUpHelper const&) 27 // f(T&, LookUpHelper2 const&) does match both but f(T&, LookUpHelper2 const&) is a 28 // perfect match (no upcast for LookUpHelper needed) 29 30 struct LookUpHelper {}; 31 struct LookUpHelper2 : public hidden::LookUpHelper {}; 32 33 // IsPtr - partial specialization only 34 template<typename T> 35 struct IsPtr { 36 enum { value = false }; 37 }; 38 template<typename T> 39 struct IsPtr<T *> { 40 enum { value = true }; 41 }; 42 } // namespace hidden 43 44 // bad_checked_cast is thrown if cast is bad 45 // see boost::lexical_cast 46 class bad_checked_cast : std::bad_cast { 47 public: 48 bad_checked_cast() : from(0), to(0) 49 {} 50 51 bad_checked_cast(std::type_info const &from, std::type_info const &to) : from(&from), to(&to) 52 {} 53 virtual ~bad_checked_cast() 54 {} 55 std::type_info const &source_type() const 56 { 57 return *from; 58 } 59 60 std::type_info const &target_type() const 61 { 62 return *to; 63 } 64 65 char const *what() const throw() 66 { 67 return "bad checked cast: source is not a target type"; 68 } 69 70 private: 71 std::type_info const *from; 72 std::type_info const *to; 73 }; 74 #ifdef CHECKED_CAST_DO_ASSERT 75 #define BAD_CHECKED_CAST(from, to) assert(false) 76 #else 77 #define BAD_CHECKED_CAST(from, to) 78 #endif 79 80 // implementation 81 namespace hidden { 82 template<typename T, typename X, bool isPtr> 83 struct checked_cast_impl; 84 85 // pointer variant 86 template<typename T, typename X> 87 struct checked_cast_impl<T, X, true> { 88 static T cast(X &x, hidden::LookUpHelper2 const &) 89 { 90 #ifdef CHECKED_CAST_SAFE_CONVERSATION 91 T t = dynamic_cast<T>(x); 92 // check cross cast 93 if (t != static_cast<T>(x)) { 94 BAD_CHECKED_CAST(x, T); 95 } 96 return t; 97 #else 98 return static_cast<T>(x); 99 #endif 100 } 101 102 static T cast(X const &x, hidden::LookUpHelper const &) 103 { 104 #ifdef CHECKED_CAST_SAFE_CONVERSATION 105 T t = dynamic_cast<T>(x); 106 107 // check cross cast 108 if (t != static_cast<T>(x)) { 109 BAD_CHECKED_CAST(x, T); 110 } 111 return t; 112 #else 113 return static_cast<T>(x); 114 #endif 115 } 116 }; 117 118 template<typename T, typename X> 119 struct checked_cast_impl<T, X, false> { 120 static T cast(X &x, hidden::LookUpHelper2 const &) 121 { 122 #ifdef CHECKED_CAST_SAFE_CONVERSATION 123 T t = dynamic_cast<T>(x); 124 // check cross cast 125 if (&t != &static_cast<T>(x)) { 126 APP_LOGE("bad cast"); 127 } 128 return t; 129 #else 130 return static_cast<T>(x); 131 #endif 132 } 133 134 static T cast(X const &x, hidden::LookUpHelper const &) 135 { 136 #ifdef CHECKED_CAST_SAFE_CONVERSATION 137 T t = dynamic_cast<T>(x); 138 // check cross cast 139 if (&t != &static_cast<T>(x)) { 140 std::bad_cast(); 141 } 142 return t; 143 #else 144 return static_cast<T>(x); 145 #endif 146 } 147 }; 148 149 } // namespace hidden 150 151 template<typename T, typename X> 152 inline T checked_cast(X &x) 153 { 154 return hidden::checked_cast_impl<T, X, hidden::IsPtr<X>::value>::cast(x, hidden::LookUpHelper2()); 155 } 156 template<typename T, typename X> 157 inline T checked_cast(X const &x) 158 { 159 return hidden::checked_cast_impl<T, X, hidden::IsPtr<X>::value>::cast(x, hidden::LookUpHelper2()); 160 } 161 162 #endif // FOUNDATION_APPEXECFWK_STANDARD_TOOLS_CHECKED_CAST_H 163