chromium/third_party/blink/renderer/platform/wtf/casting.h

// 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 "base/notreached.h"
#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 {};

DowncastTraitsHelper<Derived, Base>;

// If Derived is actually a base class of Base, unconditionally return true to
// skip the type checks.
DowncastTraitsHelper<Derived, Base>;

}  // 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) {}

template <typename Derived, typename Base>
bool IsA(const Base* from) {}

template <typename Derived, typename Base>
bool IsA(Base& from) {}

template <typename Derived, typename Base>
bool IsA(Base* 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) {}

template <typename Derived, typename Base>
const Derived* To(const Base* from) {}

template <typename Derived, typename Base>
Derived& To(Base& from) {}
template <typename Derived, typename Base>
Derived* To(Base* from) {}

// 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) {}

template <typename Derived, typename Base>
const Derived* DynamicTo(const Base& from) {}

template <typename Derived, typename Base>
Derived* DynamicTo(Base* from) {}

template <typename Derived, typename Base>
Derived* DynamicTo(Base& from) {}

// 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) {}

template <typename Derived, typename Base>
const Derived* UnsafeTo(const Base* from) {}

template <typename Derived, typename Base>
Derived& UnsafeTo(Base& from) {}
template <typename Derived, typename Base>
Derived* UnsafeTo(Base* from) {}

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_CASTING_H_