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_
|