Simplify traits, add CastableCommonBase & IsCastable
Use `static constexpr bool` instead of `std::integral_constant` for `IsTypeOrDerived`. This is often cleaner to use. Add `IsCastable`, a helper for determining if all the template types derive from `CastableBase`. Add `CastableCommonBase`, some template magic for determinine the most derived, common base type for all castable types. Change-Id: Ia3d33548424750f8260f518ecd63d39949e4a826 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/81105 Kokoro: Kokoro <noreply+kokoro@google.com> Auto-Submit: Ben Clayton <bclayton@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com> Commit-Queue: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
parent
911944cc8d
commit
473b6087ac
|
@ -48,12 +48,23 @@ namespace tint {
|
|||
// Forward declaration
|
||||
class CastableBase;
|
||||
|
||||
/// Ignore is used as a special type used for skipping over types for trait
|
||||
/// helper functions.
|
||||
class Ignore {};
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct TypeInfoOf;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// True if all template types that are not Ignore derive from CastableBase
|
||||
template <typename... TYPES>
|
||||
static constexpr bool IsCastable =
|
||||
((traits::IsTypeOrDerived<TYPES, CastableBase> ||
|
||||
std::is_same_v<TYPES, Ignore>)&&...) &&
|
||||
!(std::is_same_v<TYPES, Ignore> && ...);
|
||||
|
||||
/// Helper macro to instantiate the TypeInfo<T> template for `CLASS`.
|
||||
#define TINT_INSTANTIATE_TYPEINFO(CLASS) \
|
||||
TINT_CASTABLE_PUSH_DISABLE_WARNINGS(); \
|
||||
|
@ -145,8 +156,7 @@ struct TypeInfo {
|
|||
/// multiple hashcodes are bitwise-or'd together.
|
||||
template <typename T>
|
||||
static constexpr HashCode HashCodeOf() {
|
||||
static_assert(traits::IsTypeOrDerived<T, CastableBase>::value,
|
||||
"T is not Castable");
|
||||
static_assert(IsCastable<T>, "T is not Castable");
|
||||
static_assert(
|
||||
std::is_same_v<T, std::remove_cv_t<T>>,
|
||||
"Strip const / volatile decorations before calling HashCodeOf");
|
||||
|
@ -455,6 +465,68 @@ class Castable : public BASE {
|
|||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
/// <code>typename CastableCommonBaseImpl<TYPES>::type</code> resolves to the
|
||||
/// common base class for all of TYPES.
|
||||
template <typename... TYPES>
|
||||
struct CastableCommonBaseImpl {};
|
||||
|
||||
/// Alias to typename CastableCommonBaseImpl<TYPES>::type
|
||||
template <typename... TYPES>
|
||||
using CastableCommonBase =
|
||||
typename detail::CastableCommonBaseImpl<TYPES...>::type;
|
||||
|
||||
/// CastableCommonBaseImpl template specialization for a single type
|
||||
template <typename T>
|
||||
struct CastableCommonBaseImpl<T> {
|
||||
/// Common base class of a single type is itself
|
||||
using type = T;
|
||||
};
|
||||
|
||||
/// CastableCommonBaseImpl A <-> CastableBase specialization
|
||||
template <typename A>
|
||||
struct CastableCommonBaseImpl<A, CastableBase> {
|
||||
/// Common base class for A and CastableBase is CastableBase
|
||||
using type = CastableBase;
|
||||
};
|
||||
|
||||
/// CastableCommonBaseImpl T <-> Ignore specialization
|
||||
template <typename T>
|
||||
struct CastableCommonBaseImpl<T, Ignore> {
|
||||
/// Resolves to T as the other type is ignored
|
||||
using type = T;
|
||||
};
|
||||
|
||||
/// CastableCommonBaseImpl Ignore <-> T specialization
|
||||
template <typename T>
|
||||
struct CastableCommonBaseImpl<Ignore, T> {
|
||||
/// Resolves to T as the other type is ignored
|
||||
using type = T;
|
||||
};
|
||||
|
||||
/// CastableCommonBaseImpl A <-> B specialization
|
||||
template <typename A, typename B>
|
||||
struct CastableCommonBaseImpl<A, B> {
|
||||
/// The common base class for A, B and OTHERS
|
||||
using type = std::conditional_t<traits::IsTypeOrDerived<A, B>,
|
||||
B, // A derives from B
|
||||
CastableCommonBase<A, typename B::TrueBase>>;
|
||||
};
|
||||
|
||||
/// CastableCommonBaseImpl 3+ types specialization
|
||||
template <typename A, typename B, typename... OTHERS>
|
||||
struct CastableCommonBaseImpl<A, B, OTHERS...> {
|
||||
/// The common base class for A, B and OTHERS
|
||||
using type = CastableCommonBase<CastableCommonBase<A, B>, OTHERS...>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Resolves to the common most derived type that each of the types in `TYPES`
|
||||
/// derives from.
|
||||
template <typename... TYPES>
|
||||
using CastableCommonBase = detail::CastableCommonBase<TYPES...>;
|
||||
|
||||
/// Default can be used as the default case for a Switch(), when all previous
|
||||
/// cases failed to match.
|
||||
///
|
||||
|
|
|
@ -22,34 +22,15 @@
|
|||
namespace tint {
|
||||
namespace {
|
||||
|
||||
struct Animal : public tint::Castable<Animal> {
|
||||
explicit Animal(std::string n) : name(n) {}
|
||||
const std::string name;
|
||||
};
|
||||
|
||||
struct Amphibian : public tint::Castable<Amphibian, Animal> {
|
||||
explicit Amphibian(std::string n) : Base(n) {}
|
||||
};
|
||||
|
||||
struct Mammal : public tint::Castable<Mammal, Animal> {
|
||||
explicit Mammal(std::string n) : Base(n) {}
|
||||
};
|
||||
|
||||
struct Reptile : public tint::Castable<Reptile, Animal> {
|
||||
explicit Reptile(std::string n) : Base(n) {}
|
||||
};
|
||||
|
||||
struct Frog : public tint::Castable<Frog, Amphibian> {
|
||||
Frog() : Base("Frog") {}
|
||||
};
|
||||
|
||||
struct Bear : public tint::Castable<Bear, Mammal> {
|
||||
Bear() : Base("Bear") {}
|
||||
};
|
||||
|
||||
struct Gecko : public tint::Castable<Gecko, Reptile> {
|
||||
Gecko() : Base("Gecko") {}
|
||||
};
|
||||
struct Animal : public tint::Castable<Animal> {};
|
||||
struct Amphibian : public tint::Castable<Amphibian, Animal> {};
|
||||
struct Mammal : public tint::Castable<Mammal, Animal> {};
|
||||
struct Reptile : public tint::Castable<Reptile, Animal> {};
|
||||
struct Frog : public tint::Castable<Frog, Amphibian> {};
|
||||
struct Bear : public tint::Castable<Bear, Mammal> {};
|
||||
struct Lizard : public tint::Castable<Lizard, Reptile> {};
|
||||
struct Gecko : public tint::Castable<Gecko, Lizard> {};
|
||||
struct Iguana : public tint::Castable<Iguana, Lizard> {};
|
||||
|
||||
TEST(CastableBase, Is) {
|
||||
std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
|
||||
|
@ -417,6 +398,65 @@ TEST(Castable, SwitchNullNoDefault) {
|
|||
EXPECT_TRUE(default_called);
|
||||
}
|
||||
|
||||
// IsCastable static tests
|
||||
static_assert(IsCastable<CastableBase>);
|
||||
static_assert(IsCastable<Animal>);
|
||||
static_assert(IsCastable<Ignore, Frog, Bear>);
|
||||
static_assert(IsCastable<Mammal, Ignore, Amphibian, Gecko>);
|
||||
static_assert(!IsCastable<Mammal, int, Amphibian, Ignore, Gecko>);
|
||||
static_assert(!IsCastable<bool>);
|
||||
static_assert(!IsCastable<int, float>);
|
||||
static_assert(!IsCastable<Ignore>);
|
||||
|
||||
// CastableCommonBase static tests
|
||||
static_assert(std::is_same_v<Animal, CastableCommonBase<Animal>>);
|
||||
static_assert(std::is_same_v<Amphibian, CastableCommonBase<Amphibian>>);
|
||||
static_assert(std::is_same_v<Mammal, CastableCommonBase<Mammal>>);
|
||||
static_assert(std::is_same_v<Reptile, CastableCommonBase<Reptile>>);
|
||||
static_assert(std::is_same_v<Frog, CastableCommonBase<Frog>>);
|
||||
static_assert(std::is_same_v<Bear, CastableCommonBase<Bear>>);
|
||||
static_assert(std::is_same_v<Lizard, CastableCommonBase<Lizard>>);
|
||||
static_assert(std::is_same_v<Gecko, CastableCommonBase<Gecko>>);
|
||||
static_assert(std::is_same_v<Iguana, CastableCommonBase<Iguana>>);
|
||||
|
||||
static_assert(std::is_same_v<Animal, CastableCommonBase<Animal, Animal>>);
|
||||
static_assert(
|
||||
std::is_same_v<Amphibian, CastableCommonBase<Amphibian, Amphibian>>);
|
||||
static_assert(std::is_same_v<Mammal, CastableCommonBase<Mammal, Mammal>>);
|
||||
static_assert(std::is_same_v<Reptile, CastableCommonBase<Reptile, Reptile>>);
|
||||
static_assert(std::is_same_v<Frog, CastableCommonBase<Frog, Frog>>);
|
||||
static_assert(std::is_same_v<Bear, CastableCommonBase<Bear, Bear>>);
|
||||
static_assert(std::is_same_v<Lizard, CastableCommonBase<Lizard, Lizard>>);
|
||||
static_assert(std::is_same_v<Gecko, CastableCommonBase<Gecko, Gecko>>);
|
||||
static_assert(std::is_same_v<Iguana, CastableCommonBase<Iguana, Iguana>>);
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<CastableBase, CastableCommonBase<CastableBase, Animal>>);
|
||||
static_assert(
|
||||
std::is_same_v<CastableBase, CastableCommonBase<Animal, CastableBase>>);
|
||||
static_assert(std::is_same_v<Amphibian, CastableCommonBase<Amphibian, Frog>>);
|
||||
static_assert(std::is_same_v<Amphibian, CastableCommonBase<Frog, Amphibian>>);
|
||||
static_assert(std::is_same_v<Animal, CastableCommonBase<Reptile, Frog>>);
|
||||
static_assert(std::is_same_v<Animal, CastableCommonBase<Frog, Reptile>>);
|
||||
static_assert(std::is_same_v<Animal, CastableCommonBase<Bear, Frog>>);
|
||||
static_assert(std::is_same_v<Animal, CastableCommonBase<Frog, Bear>>);
|
||||
static_assert(std::is_same_v<Lizard, CastableCommonBase<Gecko, Iguana>>);
|
||||
|
||||
static_assert(std::is_same_v<Animal, CastableCommonBase<Bear, Frog, Iguana>>);
|
||||
static_assert(
|
||||
std::is_same_v<Lizard, CastableCommonBase<Lizard, Gecko, Iguana>>);
|
||||
static_assert(
|
||||
std::is_same_v<Lizard, CastableCommonBase<Gecko, Iguana, Lizard>>);
|
||||
static_assert(
|
||||
std::is_same_v<Lizard, CastableCommonBase<Gecko, Lizard, Iguana>>);
|
||||
static_assert(std::is_same_v<Animal, CastableCommonBase<Frog, Gecko, Iguana>>);
|
||||
static_assert(std::is_same_v<Animal, CastableCommonBase<Gecko, Iguana, Frog>>);
|
||||
static_assert(std::is_same_v<Animal, CastableCommonBase<Gecko, Frog, Iguana>>);
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<CastableBase,
|
||||
CastableCommonBase<Bear, Frog, Iguana, CastableBase>>);
|
||||
|
||||
} // namespace
|
||||
|
||||
TINT_INSTANTIATE_TYPEINFO(Animal);
|
||||
|
@ -425,6 +465,7 @@ TINT_INSTANTIATE_TYPEINFO(Mammal);
|
|||
TINT_INSTANTIATE_TYPEINFO(Reptile);
|
||||
TINT_INSTANTIATE_TYPEINFO(Frog);
|
||||
TINT_INSTANTIATE_TYPEINFO(Bear);
|
||||
TINT_INSTANTIATE_TYPEINFO(Lizard);
|
||||
TINT_INSTANTIATE_TYPEINFO(Gecko);
|
||||
|
||||
} // namespace tint
|
||||
|
|
|
@ -58,10 +58,10 @@ inline ProgramID ProgramIDOf(const Cloneable*) {
|
|||
|
||||
/// CloneContext holds the state used while cloning AST nodes.
|
||||
class CloneContext {
|
||||
/// ParamTypeIsPtrOf<F, T>::value is true iff the first parameter of
|
||||
/// ParamTypeIsPtrOf<F, T> is true iff the first parameter of
|
||||
/// F is a pointer of (or derives from) type T.
|
||||
template <typename F, typename T>
|
||||
using ParamTypeIsPtrOf = traits::IsTypeOrDerived<
|
||||
static constexpr bool ParamTypeIsPtrOf = traits::IsTypeOrDerived<
|
||||
typename std::remove_pointer<traits::ParameterType<F, 0>>::type,
|
||||
T>;
|
||||
|
||||
|
@ -295,8 +295,8 @@ class CloneContext {
|
|||
/// `T* (T*)`, where `T` derives from Cloneable
|
||||
/// @returns this CloneContext so calls can be chained
|
||||
template <typename F>
|
||||
traits::EnableIf<ParamTypeIsPtrOf<F, Cloneable>::value, CloneContext>&
|
||||
ReplaceAll(F&& replacer) {
|
||||
traits::EnableIf<ParamTypeIsPtrOf<F, Cloneable>, CloneContext>& ReplaceAll(
|
||||
F&& replacer) {
|
||||
using TPtr = traits::ParameterType<F, 0>;
|
||||
using T = typename std::remove_pointer<TPtr>::type;
|
||||
for (auto& transform : transforms_) {
|
||||
|
|
|
@ -331,8 +331,8 @@ class ProgramBuilder {
|
|||
/// @returns the node pointer
|
||||
template <typename T, typename ARG0, typename... ARGS>
|
||||
traits::EnableIf</* T is ast::Node and ARG0 is not Source */
|
||||
traits::IsTypeOrDerived<T, ast::Node>::value &&
|
||||
!traits::IsTypeOrDerived<ARG0, Source>::value,
|
||||
traits::IsTypeOrDerived<T, ast::Node> &&
|
||||
!traits::IsTypeOrDerived<ARG0, Source>,
|
||||
T>*
|
||||
create(ARG0&& arg0, ARGS&&... args) {
|
||||
AssertNotMoved();
|
||||
|
@ -346,8 +346,8 @@ class ProgramBuilder {
|
|||
/// @param args the arguments to pass to the type constructor
|
||||
/// @returns the node pointer
|
||||
template <typename T, typename... ARGS>
|
||||
traits::EnableIf<traits::IsTypeOrDerived<T, sem::Node>::value &&
|
||||
!traits::IsTypeOrDerived<T, sem::Type>::value,
|
||||
traits::EnableIf<traits::IsTypeOrDerived<T, sem::Node> &&
|
||||
!traits::IsTypeOrDerived<T, sem::Type>,
|
||||
T>*
|
||||
create(ARGS&&... args) {
|
||||
AssertNotMoved();
|
||||
|
|
15
src/traits.h
15
src/traits.h
|
@ -86,13 +86,12 @@ using ParameterType = typename SignatureOfT<F>::template parameter<N>;
|
|||
template <typename F>
|
||||
using ReturnType = typename SignatureOfT<F>::ret;
|
||||
|
||||
/// `IsTypeOrDerived<T, BASE>::value` is true iff `T` is of type `BASE`, or
|
||||
/// derives from `BASE`.
|
||||
/// IsTypeOrDerived<T, BASE> is true iff `T` is of type `BASE`, or derives from
|
||||
/// `BASE`.
|
||||
template <typename T, typename BASE>
|
||||
using IsTypeOrDerived =
|
||||
std::integral_constant<bool,
|
||||
std::is_base_of<BASE, Decay<T>>::value ||
|
||||
std::is_same<BASE, Decay<T>>::value>;
|
||||
static constexpr bool IsTypeOrDerived =
|
||||
std::is_base_of<BASE, Decay<T>>::value ||
|
||||
std::is_same<BASE, Decay<T>>::value;
|
||||
|
||||
/// If `CONDITION` is true then EnableIf resolves to type T, otherwise an
|
||||
/// invalid type.
|
||||
|
@ -102,12 +101,12 @@ using EnableIf = typename std::enable_if<CONDITION, T>::type;
|
|||
/// If `T` is of type `BASE`, or derives from `BASE`, then EnableIfIsType
|
||||
/// resolves to type `T`, otherwise an invalid type.
|
||||
template <typename T, typename BASE>
|
||||
using EnableIfIsType = EnableIf<IsTypeOrDerived<T, BASE>::value, T>;
|
||||
using EnableIfIsType = EnableIf<IsTypeOrDerived<T, BASE>, T>;
|
||||
|
||||
/// If `T` is not of type `BASE`, or does not derive from `BASE`, then
|
||||
/// EnableIfIsNotType resolves to type `T`, otherwise an invalid type.
|
||||
template <typename T, typename BASE>
|
||||
using EnableIfIsNotType = EnableIf<!IsTypeOrDerived<T, BASE>::value, T>;
|
||||
using EnableIfIsNotType = EnableIf<!IsTypeOrDerived<T, BASE>, T>;
|
||||
|
||||
/// @returns the std::index_sequence with all the indices shifted by OFFSET.
|
||||
template <std::size_t OFFSET, std::size_t... INDICES>
|
||||
|
|
Loading…
Reference in New Issue