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:
bad_checked_cast()48 bad_checked_cast() : from(0), to(0)
49 {}
50
bad_checked_cast(std::type_info const &from, std::type_info const &to)51 bad_checked_cast(std::type_info const &from, std::type_info const &to) : from(&from), to(&to)
52 {}
~bad_checked_cast()53 virtual ~bad_checked_cast()
54 {}
source_type() const55 std::type_info const &source_type() const
56 {
57 return *from;
58 }
59
target_type() const60 std::type_info const &target_type() const
61 {
62 return *to;
63 }
64
what() const65 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> {
casthidden::checked_cast_impl88 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
casthidden::checked_cast_impl102 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> {
casthidden::checked_cast_impl120 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
casthidden::checked_cast_impl134 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>
checked_cast(X &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>
checked_cast(X const &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