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