blob: 0c0429be594b2134777f187edcfd7018685fcc55 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// 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_CORE_LAYOUT_NG_TABLE_INTERFACE_CASTING_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_TABLE_INTERFACE_CASTING_H_
#include "base/notreached.h"
namespace blink {
// These are the helpers for downcasting to mixin classes.
//
// Given the following class hierarchy:
//
// class BaseClass;
// class MixinClass;
// class DerivedOne : public BaseClass, public MixinClass;
// class DerivedTwo : public BaseClass, public MixinClass;
//
// There is no way to convert BaseClass to MixingClass by c++ casting.
//
// Instead, we must declare a casting helper methods on BaseClass:
//
// class BaseClass {
// virtual const MixinClass* ToMixin() const {
// DCHECK(false);
// return nullptr;
// }
// }
//
// and override them in derived classes:
//
// class DerivedOne : public BaseClass, public MixinClass {
// const MixinClass* ToMixin() const override {
// return this;
// }
// }
//
// These templates try to make mixin casting feel similar to downcasting
// primitives from wtf/casting.h
//
// Mixin casting is implemented by specializing InterfaceDowncastTraits:
//
// struct InterfaceDowncastTraits<MixingClass> {
// static bool AllowFrom(const BaseClass& b) {
// return b.IsDerivedClassWithMixin();
// }
// static const MixingClass& ConvertFrom(const BaseClass& b) {
// return b.ToMixin();
// }
// };
template <typename T>
struct InterfaceDowncastTraits {
template <typename U>
static bool AllowFrom(const U&) {
static_assert(sizeof(U) == 0, "no downcast traits specialization for T");
NOTREACHED();
return false;
}
template <typename U>
static const T& ConvertFrom(const U&) {
static_assert(sizeof(U) == 0, "no downcast traits specialization for T");
}
};
template <typename Derived, typename Base>
const Derived& ToInterface(const Base& from) {
SECURITY_DCHECK(InterfaceDowncastTraits<Derived>::AllowFrom(from));
return InterfaceDowncastTraits<Derived>::ConvertFrom(from);
}
template <typename Derived, typename Base>
const Derived* ToInterface(const Base* from) {
if (from)
SECURITY_DCHECK(InterfaceDowncastTraits<Derived>::AllowFrom(*from));
return from ? &InterfaceDowncastTraits<Derived>::ConvertFrom(*from) : nullptr;
}
template <typename Derived, typename Base>
Derived& ToInterface(Base& from) {
SECURITY_DCHECK(InterfaceDowncastTraits<Derived>::AllowFrom(from));
// const_cast is safe because from is not const.
return const_cast<Derived&>(
InterfaceDowncastTraits<Derived>::ConvertFrom(*from));
}
template <typename Derived, typename Base>
Derived* ToInterface(Base* from) {
if (from)
SECURITY_DCHECK(InterfaceDowncastTraits<Derived>::AllowFrom(*from));
// const_cast is safe because from is not const.
return from ? const_cast<Derived*>(
&InterfaceDowncastTraits<Derived>::ConvertFrom(*from))
: nullptr;
}
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_TABLE_INTERFACE_CASTING_H_