1/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations 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
23namespace 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
49template <typename To, typename From> // use like this: down_cast<T*>(foo);
50inline 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.
72template <typename To, typename From>
73inline 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