1 | /* Copyright 2020 The TensorFlow Authors. All Rights Reserved. |
2 | |
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 | |
16 | #ifndef TENSORFLOW_TSL_PLATFORM_DEFAULT_CASTS_H_ |
17 | #define TENSORFLOW_TSL_PLATFORM_DEFAULT_CASTS_H_ |
18 | |
19 | #include <assert.h> // for use with down_cast<> |
20 | |
21 | #include <type_traits> |
22 | |
23 | namespace tensorflow { |
24 | |
25 | // An "upcast", i.e. a conversion from a pointer to an object to a pointer to a |
26 | // base subobject, always succeeds if the base is unambiguous and accessible, |
27 | // and so it's fine to use implicit_cast. |
28 | // |
29 | // A "downcast", i.e. a conversion from a pointer to an object to a pointer |
30 | // to a more-derived object that may contain the original object as a base |
31 | // subobject, cannot safely be done using static_cast, because you do not |
32 | // generally know whether the source object is really the base subobject of |
33 | // a containing, more-derived object of the target type. Thus, when you |
34 | // downcast in a polymorphic type hierarchy, you should use the following |
35 | // function template. |
36 | // |
37 | // In debug mode, we use dynamic_cast to double-check whether the downcast is |
38 | // legal (we die if it's not). In normal mode, we do the efficient static_cast |
39 | // instead. Thus, it's important to test in debug mode to make sure the cast is |
40 | // legal! |
41 | // |
42 | // This is the only place in the codebase we should use dynamic_cast. |
43 | // In particular, you should NOT use dynamic_cast for RTTI, e.g. for |
44 | // code like this: |
45 | // if (auto* p = dynamic_cast<Subclass1*>(foo)) HandleASubclass1Object(p); |
46 | // if (auto* p = dynamic_cast<Subclass2*>(foo)) HandleASubclass2Object(p); |
47 | // You should design the code some other way not to need this. |
48 | |
49 | template <typename To, typename From> // use like this: down_cast<T*>(foo); |
50 | inline To down_cast(From* f) { // so we only accept pointers |
51 | static_assert( |
52 | (std::is_base_of<From, typename std::remove_pointer<To>::type>::value), |
53 | "target type not derived from source type" ); |
54 | |
55 | // We skip the assert and hence the dynamic_cast if RTTI is disabled. |
56 | #if !defined(__GNUC__) || defined(__GXX_RTTI) |
57 | // Uses RTTI in dbg and fastbuild. asserts are disabled in opt builds. |
58 | assert(f == nullptr || dynamic_cast<To>(f) != nullptr); |
59 | #endif // !defined(__GNUC__) || defined(__GXX_RTTI) |
60 | |
61 | return static_cast<To>(f); |
62 | } |
63 | |
64 | // Overload of down_cast for references. Use like this: down_cast<T&>(foo). |
65 | // The code is slightly convoluted because we're still using the pointer |
66 | // form of dynamic cast. (The reference form throws an exception if it |
67 | // fails.) |
68 | // |
69 | // There's no need for a special const overload either for the pointer |
70 | // or the reference form. If you call down_cast with a const T&, the |
71 | // compiler will just bind From to const T. |
72 | template <typename To, typename From> |
73 | inline To down_cast(From& f) { |
74 | static_assert(std::is_lvalue_reference<To>::value, |
75 | "target type not a reference" ); |
76 | static_assert( |
77 | (std::is_base_of<From, typename std::remove_reference<To>::type>::value), |
78 | "target type not derived from source type" ); |
79 | |
80 | // We skip the assert and hence the dynamic_cast if RTTI is disabled. |
81 | #if !defined(__GNUC__) || defined(__GXX_RTTI) |
82 | // RTTI: debug mode only |
83 | assert(dynamic_cast<typename std::remove_reference<To>::type*>(&f) != |
84 | nullptr); |
85 | #endif // !defined(__GNUC__) || defined(__GXX_RTTI) |
86 | |
87 | return static_cast<To>(f); |
88 | } |
89 | |
90 | } // namespace tensorflow |
91 | |
92 | #endif // TENSORFLOW_TSL_PLATFORM_DEFAULT_CASTS_H_ |
93 | |