File: casting.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (203 lines) | stat: -rw-r--r-- 7,332 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_CASTING_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_CASTING_H_

#include <concepts>
#include <type_traits>

#include "third_party/blink/renderer/platform/wtf/assertions.h"

namespace blink {

// Helpers for downcasting in a class hierarchy.
//
//   IsA<T>(x): returns true if |x| can be safely downcast to T*. Usage of this
//       should not be common; if it is paired with a call to To<T>, consider
//       using DynamicTo<T> instead (see below). Note that this also returns
//       false if |x| is nullptr.
//
//   To<T>(x): unconditionally downcasts and returns |x| as a T*. CHECKs if the
//       downcast is unsafe. Use when IsA<T>(x) is known to be true due to
//       external invariants and not on a performance sensitive path.
//       If |x| is nullptr, returns nullptr.
//
//   DynamicTo<T>(x): downcasts and returns |x| as a T* iff IsA<T>(x) is true,
//       and nullptr otherwise. This is useful for combining a conditional
//       branch on IsA<T>(x) and an invocation of To<T>(x), e.g.:
//           if (IsA<DerivedClass>(x))
//             To<DerivedClass>(x)->...
//       can be written:
//           if (auto* derived = DynamicTo<DerivedClass>(x))
//             derived->...;
//
//   UnsafeTo<T>(x): unconditionally downcasts and returns |x| as a T*. DCHECKs
//       if the downcast is unsafe. Use when IsA<T>(x) is known to be true due
//       to external invariants. Prefer To<T> over this method, but this is ok
//       to use in performance sensitive code. If |x| is nullptr, returns
//       nullptr.
//
// Marking downcasts as safe is done by specializing the DowncastTraits
// template:
//
// template <>
// struct DowncastTraits<DerivedClass> {
//   static bool AllowFrom(const BaseClass& b) {
//     return b.IsDerivedClass();
//   }
//   static bool AllowFrom(const AnotherBaseClass& b) {
//     return b.type() == AnotherBaseClass::kDerivedClassTag;
//   }
// };
//
// int main() {
//   BaseClass* base = CreateDerived();
//   AnotherBaseClass* another_base = CreateDerived();
//   UnrelatedClass* unrelated = CreateUnrelated();
//
//   std::cout << std::boolalpha;
//   std::cout << IsA<Derived>(base) << '\n';          // prints true
//   std::cout << IsA<Derived>(another_base) << '\n';  // prints true
//   std::cout << IsA<Derived>(unrelated) << '\n';     // prints false
// }
template <typename Derived>
struct DowncastTraits;

namespace internal {

template <typename Derived, typename Base>
struct DowncastTraitsHelper {
  static_assert(sizeof(Derived) == 0,
                "Unknown type, this error typically means you need to include "
                "the header of the type being cast to.");
};

template <typename Derived, typename Base>
  requires(!std::is_base_of_v<Derived, Base>)
struct DowncastTraitsHelper<Derived, Base> {
  static bool AllowFrom(const Base& from) {
    return DowncastTraits<Derived>::AllowFrom(from);
  }
};

// If Derived is actually a base class of Base, unconditionally return true to
// skip the type checks.
template <typename Derived, typename Base>
  requires(std::is_base_of_v<Derived, Base>)
struct DowncastTraitsHelper<Derived, Base> {
  static bool AllowFrom(const Base&) { return true; }
};

}  // namespace internal

// Returns true iff the conversion from Base to Derived is allowed. For the
// pointer overloads, returns false if the input pointer is nullptr.
template <typename Derived, typename Base>
bool IsA(const Base& from) {
  static_assert(std::is_base_of_v<Base, Derived>, "Unnecessary type check");
  return internal::DowncastTraitsHelper<Derived, const Base>::AllowFrom(from);
}

template <typename Derived, typename Base>
bool IsA(const Base* from) {
  static_assert(std::is_base_of_v<Base, Derived>, "Unnecessary type check");
  return from && IsA<Derived>(*from);
}

template <typename Derived, typename Base>
bool IsA(Base& from) {
  static_assert(std::is_base_of_v<Base, Derived>, "Unnecessary type check");
  return internal::DowncastTraitsHelper<Derived, const Base>::AllowFrom(
      const_cast<const Base&>(from));
}

template <typename Derived, typename Base>
bool IsA(Base* from) {
  static_assert(std::is_base_of_v<Base, Derived>, "Unnecessary type check");
  return from && IsA<Derived>(*from);
}

// Unconditionally downcasts from Base to Derived. Internally, this asserts that
// |from| is a Derived to help catch bad casts. For the pointer overloads,
// returns nullptr if the input pointer is nullptr.
template <typename Derived, typename Base>
const Derived& To(const Base& from) {
  CHECK(IsA<Derived>(from));
  return static_cast<const Derived&>(from);
}

template <typename Derived, typename Base>
const Derived* To(const Base* from) {
  return from ? &To<Derived>(*from) : nullptr;
}

template <typename Derived, typename Base>
Derived& To(Base& from) {
  CHECK(IsA<Derived>(from));
  return static_cast<Derived&>(from);
}
template <typename Derived, typename Base>
Derived* To(Base* from) {
  return from ? &To<Derived>(*from) : nullptr;
}

// Safely downcasts from Base to Derived. If |from| is not a Derived, returns
// nullptr; otherwise, downcasts from Base to Derived. For the pointer
// overloads, returns nullptr if the input pointer is nullptr.
template <typename Derived, typename Base>
const Derived* DynamicTo(const Base* from) {
  // TOOD(https://crbug.com/1449302): Figure out why IsA<T> + To<T> does not
  // optimize correctly.
  return IsA<Derived>(from) ? static_cast<const Derived*>(from) : nullptr;
}

template <typename Derived, typename Base>
const Derived* DynamicTo(const Base& from) {
  // TOOD(https://crbug.com/1449302): Figure out why IsA<T> + To<T> does not
  // optimize correctly.
  return IsA<Derived>(from) ? &static_cast<const Derived&>(from) : nullptr;
}

template <typename Derived, typename Base>
Derived* DynamicTo(Base* from) {
  // TOOD(https://crbug.com/1449302): Figure out why IsA<T> + To<T> does not
  // optimize correctly.
  return IsA<Derived>(from) ? static_cast<Derived*>(from) : nullptr;
}

template <typename Derived, typename Base>
Derived* DynamicTo(Base& from) {
  // TOOD(https://crbug.com/1449302): Figure out why IsA<T> + To<T> does not
  // optimize correctly.
  return IsA<Derived>(from) ? &static_cast<Derived&>(from) : nullptr;
}

// Unconditionally downcasts from Base to Derived. Internally, this asserts
// that |from| is a Derived to help catch bad casts in testing/fuzzing. For the
// pointer overloads, returns nullptr if the input pointer is nullptr.
template <typename Derived, typename Base>
const Derived& UnsafeTo(const Base& from) {
  SECURITY_DCHECK(IsA<Derived>(from));
  return static_cast<const Derived&>(from);
}

template <typename Derived, typename Base>
const Derived* UnsafeTo(const Base* from) {
  return from ? &UnsafeTo<Derived>(*from) : nullptr;
}

template <typename Derived, typename Base>
Derived& UnsafeTo(Base& from) {
  SECURITY_DCHECK(IsA<Derived>(from));
  return static_cast<Derived&>(from);
}
template <typename Derived, typename Base>
Derived* UnsafeTo(Base* from) {
  return from ? &UnsafeTo<Derived>(*from) : nullptr;
}

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_CASTING_H_