1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_CASTING_H_
6 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_CASTING_H_
7 
8 #include "third_party/blink/renderer/platform/wtf/assertions.h"
9 
10 namespace blink {
11 
12 // Helpers for downcasting in a class hierarchy.
13 //
14 //   IsA<T>(x): returns true if |x| can be safely downcast to T*. Usage of this
15 //       should not be common; if it is paired with a call to To<T>, consider
16 //       using DynamicTo<T> instead (see below). Note that this also returns
17 //       false if |x| is nullptr.
18 //
19 //   To<T>(x): unconditionally downcasts and returns |x| as a T*. DCHECKs if the
20 //       downcast is unsafe. Use when IsA<T>(x) is known to be true due to
21 //       external invariants. If |x| is nullptr, returns nullptr.
22 //
23 //   DynamicTo<T>(x): downcasts and returns |x| as a T* iff IsA<T>(x) is true,
24 //       and nullptr otherwise. This is useful for combining a conditional
25 //       branch on IsA<T>(x) and an invocation of To<T>(x), e.g.:
26 //           if (IsA<DerivedClass>(x))
27 //             To<DerivedClass>(x)->...
28 //       can be written:
29 //           if (auto* derived = DynamicTo<DerivedClass>(x))
30 //             derived->...;
31 //
32 // Marking downcasts as safe is done by specializing the DowncastTraits
33 // template:
34 //
35 // template <>
36 // struct DowncastTraits<DerivedClass> {
37 //   static bool AllowFrom(const BaseClass& b) {
38 //     return b.IsDerivedClass();
39 //   }
40 //   static bool AllowFrom(const AnotherBaseClass& b) {
41 //     return b.type() == AnotherBaseClass::kDerivedClassTag;
42 //   }
43 // };
44 //
45 // int main() {
46 //   BaseClass* base = CreateDerived();
47 //   AnotherBaseClass* another_base = CreateDerived();
48 //   UnrelatedClass* unrelated = CreateUnrelated();
49 //
50 //   std::cout << std::boolalpha;
51 //   std::cout << IsA<Derived>(base) << '\n';          // prints true
52 //   std::cout << IsA<Derived>(another_base) << '\n';  // prints true
53 //   std::cout << IsA<Derived>(unrelated) << '\n';     // prints false
54 // }
55 template <typename T>
56 struct DowncastTraits {
57   template <typename U>
AllowFromDowncastTraits58   static bool AllowFrom(const U&) {
59     static_assert(sizeof(U) == 0, "no downcast traits specialization for T");
60   }
61 };
62 
63 // Returns true iff the conversion from Base to Derived is allowed. For the
64 // pointer overloads, returns false if the input pointer is nullptr.
65 template <typename Derived, typename Base>
IsA(const Base & from)66 bool IsA(const Base& from) {
67   return DowncastTraits<Derived>::AllowFrom(from);
68 }
69 
70 template <typename Derived, typename Base>
IsA(const Base * from)71 bool IsA(const Base* from) {
72   return from && IsA<Derived>(*from);
73 }
74 
75 template <typename Derived, typename Base>
IsA(Base & from)76 bool IsA(Base& from) {
77   return IsA<Derived>(static_cast<const Base&>(from));
78 }
79 
80 template <typename Derived, typename Base>
IsA(Base * from)81 bool IsA(Base* from) {
82   return from && IsA<Derived>(*from);
83 }
84 
85 // Unconditionally downcasts from Base to Derived. Internally, this asserts
86 // that |from| is a Derived to help catch bad casts in testing/fuzzing. For the
87 // pointer overloads, returns nullptr if the input pointer is nullptr.
88 template <typename Derived, typename Base>
To(const Base & from)89 const Derived& To(const Base& from) {
90   SECURITY_DCHECK(IsA<Derived>(from));
91   return static_cast<const Derived&>(from);
92 }
93 
94 template <typename Derived, typename Base>
To(const Base * from)95 const Derived* To(const Base* from) {
96   return from ? &To<Derived>(*from) : nullptr;
97 }
98 
99 template <typename Derived, typename Base>
To(Base & from)100 Derived& To(Base& from) {
101   SECURITY_DCHECK(IsA<Derived>(from));
102   return static_cast<Derived&>(from);
103 }
104 template <typename Derived, typename Base>
To(Base * from)105 Derived* To(Base* from) {
106   return from ? &To<Derived>(*from) : nullptr;
107 }
108 
109 // Safely downcasts from Base to Derived. If |from| is not a Derived, returns
110 // nullptr; otherwise, downcasts from Base to Derived. For the pointer
111 // overloads, returns nullptr if the input pointer is nullptr.
112 template <typename Derived, typename Base>
DynamicTo(const Base * from)113 const Derived* DynamicTo(const Base* from) {
114   return IsA<Derived>(from) ? To<Derived>(from) : nullptr;
115 }
116 
117 template <typename Derived, typename Base>
DynamicTo(const Base & from)118 const Derived* DynamicTo(const Base& from) {
119   return IsA<Derived>(from) ? &To<Derived>(from) : nullptr;
120 }
121 
122 template <typename Derived, typename Base>
DynamicTo(Base * from)123 Derived* DynamicTo(Base* from) {
124   return IsA<Derived>(from) ? To<Derived>(from) : nullptr;
125 }
126 
127 template <typename Derived, typename Base>
DynamicTo(Base & from)128 Derived* DynamicTo(Base& from) {
129   return IsA<Derived>(from) ? &To<Derived>(from) : nullptr;
130 }
131 
132 }  // namespace blink
133 
134 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_CASTING_H_
135