diff --git a/src/castable.h b/src/castable.h index 8977467ffa..2906563dfd 100644 --- a/src/castable.h +++ b/src/castable.h @@ -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 struct TypeInfoOf; } // namespace detail +/// True if all template types that are not Ignore derive from CastableBase +template +static constexpr bool IsCastable = + ((traits::IsTypeOrDerived || + std::is_same_v)&&...) && + !(std::is_same_v && ...); + /// Helper macro to instantiate the TypeInfo 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 static constexpr HashCode HashCodeOf() { - static_assert(traits::IsTypeOrDerived::value, - "T is not Castable"); + static_assert(IsCastable, "T is not Castable"); static_assert( std::is_same_v>, "Strip const / volatile decorations before calling HashCodeOf"); @@ -455,6 +465,68 @@ class Castable : public BASE { } }; +namespace detail { +/// typename CastableCommonBaseImpl::type resolves to the +/// common base class for all of TYPES. +template +struct CastableCommonBaseImpl {}; + +/// Alias to typename CastableCommonBaseImpl::type +template +using CastableCommonBase = + typename detail::CastableCommonBaseImpl::type; + +/// CastableCommonBaseImpl template specialization for a single type +template +struct CastableCommonBaseImpl { + /// Common base class of a single type is itself + using type = T; +}; + +/// CastableCommonBaseImpl A <-> CastableBase specialization +template +struct CastableCommonBaseImpl { + /// Common base class for A and CastableBase is CastableBase + using type = CastableBase; +}; + +/// CastableCommonBaseImpl T <-> Ignore specialization +template +struct CastableCommonBaseImpl { + /// Resolves to T as the other type is ignored + using type = T; +}; + +/// CastableCommonBaseImpl Ignore <-> T specialization +template +struct CastableCommonBaseImpl { + /// Resolves to T as the other type is ignored + using type = T; +}; + +/// CastableCommonBaseImpl A <-> B specialization +template +struct CastableCommonBaseImpl { + /// The common base class for A, B and OTHERS + using type = std::conditional_t, + B, // A derives from B + CastableCommonBase>; +}; + +/// CastableCommonBaseImpl 3+ types specialization +template +struct CastableCommonBaseImpl { + /// The common base class for A, B and OTHERS + using type = CastableCommonBase, OTHERS...>; +}; + +} // namespace detail + +/// Resolves to the common most derived type that each of the types in `TYPES` +/// derives from. +template +using CastableCommonBase = detail::CastableCommonBase; + /// Default can be used as the default case for a Switch(), when all previous /// cases failed to match. /// diff --git a/src/castable_test.cc b/src/castable_test.cc index a15b3d6f35..4975bef964 100644 --- a/src/castable_test.cc +++ b/src/castable_test.cc @@ -22,34 +22,15 @@ namespace tint { namespace { -struct Animal : public tint::Castable { - explicit Animal(std::string n) : name(n) {} - const std::string name; -}; - -struct Amphibian : public tint::Castable { - explicit Amphibian(std::string n) : Base(n) {} -}; - -struct Mammal : public tint::Castable { - explicit Mammal(std::string n) : Base(n) {} -}; - -struct Reptile : public tint::Castable { - explicit Reptile(std::string n) : Base(n) {} -}; - -struct Frog : public tint::Castable { - Frog() : Base("Frog") {} -}; - -struct Bear : public tint::Castable { - Bear() : Base("Bear") {} -}; - -struct Gecko : public tint::Castable { - Gecko() : Base("Gecko") {} -}; +struct Animal : public tint::Castable {}; +struct Amphibian : public tint::Castable {}; +struct Mammal : public tint::Castable {}; +struct Reptile : public tint::Castable {}; +struct Frog : public tint::Castable {}; +struct Bear : public tint::Castable {}; +struct Lizard : public tint::Castable {}; +struct Gecko : public tint::Castable {}; +struct Iguana : public tint::Castable {}; TEST(CastableBase, Is) { std::unique_ptr frog = std::make_unique(); @@ -417,6 +398,65 @@ TEST(Castable, SwitchNullNoDefault) { EXPECT_TRUE(default_called); } +// IsCastable static tests +static_assert(IsCastable); +static_assert(IsCastable); +static_assert(IsCastable); +static_assert(IsCastable); +static_assert(!IsCastable); +static_assert(!IsCastable); +static_assert(!IsCastable); +static_assert(!IsCastable); + +// CastableCommonBase static tests +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +static_assert(std::is_same_v>); +static_assert( + std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +static_assert( + std::is_same_v>); +static_assert( + std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +static_assert(std::is_same_v>); +static_assert( + std::is_same_v>); +static_assert( + std::is_same_v>); +static_assert( + std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +static_assert( + std::is_same_v>); + } // 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 diff --git a/src/clone_context.h b/src/clone_context.h index 974ee90876..4037e80f5e 100644 --- a/src/clone_context.h +++ b/src/clone_context.h @@ -58,10 +58,10 @@ inline ProgramID ProgramIDOf(const Cloneable*) { /// CloneContext holds the state used while cloning AST nodes. class CloneContext { - /// ParamTypeIsPtrOf::value is true iff the first parameter of + /// ParamTypeIsPtrOf is true iff the first parameter of /// F is a pointer of (or derives from) type T. template - using ParamTypeIsPtrOf = traits::IsTypeOrDerived< + static constexpr bool ParamTypeIsPtrOf = traits::IsTypeOrDerived< typename std::remove_pointer>::type, T>; @@ -295,8 +295,8 @@ class CloneContext { /// `T* (T*)`, where `T` derives from Cloneable /// @returns this CloneContext so calls can be chained template - traits::EnableIf::value, CloneContext>& - ReplaceAll(F&& replacer) { + traits::EnableIf, CloneContext>& ReplaceAll( + F&& replacer) { using TPtr = traits::ParameterType; using T = typename std::remove_pointer::type; for (auto& transform : transforms_) { diff --git a/src/program_builder.h b/src/program_builder.h index 0db8eea5fc..787b64eb28 100644 --- a/src/program_builder.h +++ b/src/program_builder.h @@ -331,8 +331,8 @@ class ProgramBuilder { /// @returns the node pointer template traits::EnableIf::value && - !traits::IsTypeOrDerived::value, + traits::IsTypeOrDerived && + !traits::IsTypeOrDerived, 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 - traits::EnableIf::value && - !traits::IsTypeOrDerived::value, + traits::EnableIf && + !traits::IsTypeOrDerived, T>* create(ARGS&&... args) { AssertNotMoved(); diff --git a/src/traits.h b/src/traits.h index f8e52a603a..ef702d6013 100644 --- a/src/traits.h +++ b/src/traits.h @@ -86,13 +86,12 @@ using ParameterType = typename SignatureOfT::template parameter; template using ReturnType = typename SignatureOfT::ret; -/// `IsTypeOrDerived::value` is true iff `T` is of type `BASE`, or -/// derives from `BASE`. +/// IsTypeOrDerived is true iff `T` is of type `BASE`, or derives from +/// `BASE`. template -using IsTypeOrDerived = - std::integral_constant>::value || - std::is_same>::value>; +static constexpr bool IsTypeOrDerived = + std::is_base_of>::value || + std::is_same>::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::type; /// If `T` is of type `BASE`, or derives from `BASE`, then EnableIfIsType /// resolves to type `T`, otherwise an invalid type. template -using EnableIfIsType = EnableIf::value, T>; +using EnableIfIsType = EnableIf, 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 -using EnableIfIsNotType = EnableIf::value, T>; +using EnableIfIsNotType = EnableIf, T>; /// @returns the std::index_sequence with all the indices shifted by OFFSET. template