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
|
// Forward declaration
|
||||||
class CastableBase;
|
class CastableBase;
|
||||||
|
|
||||||
|
/// Ignore is used as a special type used for skipping over types for trait
|
||||||
|
/// helper functions.
|
||||||
|
class Ignore {};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct TypeInfoOf;
|
struct TypeInfoOf;
|
||||||
|
|
||||||
} // namespace detail
|
} // 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`.
|
/// Helper macro to instantiate the TypeInfo<T> template for `CLASS`.
|
||||||
#define TINT_INSTANTIATE_TYPEINFO(CLASS) \
|
#define TINT_INSTANTIATE_TYPEINFO(CLASS) \
|
||||||
TINT_CASTABLE_PUSH_DISABLE_WARNINGS(); \
|
TINT_CASTABLE_PUSH_DISABLE_WARNINGS(); \
|
||||||
|
@ -145,8 +156,7 @@ struct TypeInfo {
|
||||||
/// multiple hashcodes are bitwise-or'd together.
|
/// multiple hashcodes are bitwise-or'd together.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr HashCode HashCodeOf() {
|
static constexpr HashCode HashCodeOf() {
|
||||||
static_assert(traits::IsTypeOrDerived<T, CastableBase>::value,
|
static_assert(IsCastable<T>, "T is not Castable");
|
||||||
"T is not Castable");
|
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_same_v<T, std::remove_cv_t<T>>,
|
std::is_same_v<T, std::remove_cv_t<T>>,
|
||||||
"Strip const / volatile decorations before calling HashCodeOf");
|
"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
|
/// Default can be used as the default case for a Switch(), when all previous
|
||||||
/// cases failed to match.
|
/// cases failed to match.
|
||||||
///
|
///
|
||||||
|
|
|
@ -22,34 +22,15 @@
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct Animal : public tint::Castable<Animal> {
|
struct Animal : public tint::Castable<Animal> {};
|
||||||
explicit Animal(std::string n) : name(n) {}
|
struct Amphibian : public tint::Castable<Amphibian, Animal> {};
|
||||||
const std::string name;
|
struct Mammal : public tint::Castable<Mammal, Animal> {};
|
||||||
};
|
struct Reptile : public tint::Castable<Reptile, Animal> {};
|
||||||
|
struct Frog : public tint::Castable<Frog, Amphibian> {};
|
||||||
struct Amphibian : public tint::Castable<Amphibian, Animal> {
|
struct Bear : public tint::Castable<Bear, Mammal> {};
|
||||||
explicit Amphibian(std::string n) : Base(n) {}
|
struct Lizard : public tint::Castable<Lizard, Reptile> {};
|
||||||
};
|
struct Gecko : public tint::Castable<Gecko, Lizard> {};
|
||||||
|
struct Iguana : public tint::Castable<Iguana, Lizard> {};
|
||||||
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") {}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(CastableBase, Is) {
|
TEST(CastableBase, Is) {
|
||||||
std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
|
std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
|
||||||
|
@ -417,6 +398,65 @@ TEST(Castable, SwitchNullNoDefault) {
|
||||||
EXPECT_TRUE(default_called);
|
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
|
} // namespace
|
||||||
|
|
||||||
TINT_INSTANTIATE_TYPEINFO(Animal);
|
TINT_INSTANTIATE_TYPEINFO(Animal);
|
||||||
|
@ -425,6 +465,7 @@ TINT_INSTANTIATE_TYPEINFO(Mammal);
|
||||||
TINT_INSTANTIATE_TYPEINFO(Reptile);
|
TINT_INSTANTIATE_TYPEINFO(Reptile);
|
||||||
TINT_INSTANTIATE_TYPEINFO(Frog);
|
TINT_INSTANTIATE_TYPEINFO(Frog);
|
||||||
TINT_INSTANTIATE_TYPEINFO(Bear);
|
TINT_INSTANTIATE_TYPEINFO(Bear);
|
||||||
|
TINT_INSTANTIATE_TYPEINFO(Lizard);
|
||||||
TINT_INSTANTIATE_TYPEINFO(Gecko);
|
TINT_INSTANTIATE_TYPEINFO(Gecko);
|
||||||
|
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -58,10 +58,10 @@ inline ProgramID ProgramIDOf(const Cloneable*) {
|
||||||
|
|
||||||
/// CloneContext holds the state used while cloning AST nodes.
|
/// CloneContext holds the state used while cloning AST nodes.
|
||||||
class CloneContext {
|
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.
|
/// F is a pointer of (or derives from) type T.
|
||||||
template <typename F, typename 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,
|
typename std::remove_pointer<traits::ParameterType<F, 0>>::type,
|
||||||
T>;
|
T>;
|
||||||
|
|
||||||
|
@ -295,8 +295,8 @@ class CloneContext {
|
||||||
/// `T* (T*)`, where `T` derives from Cloneable
|
/// `T* (T*)`, where `T` derives from Cloneable
|
||||||
/// @returns this CloneContext so calls can be chained
|
/// @returns this CloneContext so calls can be chained
|
||||||
template <typename F>
|
template <typename F>
|
||||||
traits::EnableIf<ParamTypeIsPtrOf<F, Cloneable>::value, CloneContext>&
|
traits::EnableIf<ParamTypeIsPtrOf<F, Cloneable>, CloneContext>& ReplaceAll(
|
||||||
ReplaceAll(F&& replacer) {
|
F&& replacer) {
|
||||||
using TPtr = traits::ParameterType<F, 0>;
|
using TPtr = traits::ParameterType<F, 0>;
|
||||||
using T = typename std::remove_pointer<TPtr>::type;
|
using T = typename std::remove_pointer<TPtr>::type;
|
||||||
for (auto& transform : transforms_) {
|
for (auto& transform : transforms_) {
|
||||||
|
|
|
@ -331,8 +331,8 @@ class ProgramBuilder {
|
||||||
/// @returns the node pointer
|
/// @returns the node pointer
|
||||||
template <typename T, typename ARG0, typename... ARGS>
|
template <typename T, typename ARG0, typename... ARGS>
|
||||||
traits::EnableIf</* T is ast::Node and ARG0 is not Source */
|
traits::EnableIf</* T is ast::Node and ARG0 is not Source */
|
||||||
traits::IsTypeOrDerived<T, ast::Node>::value &&
|
traits::IsTypeOrDerived<T, ast::Node> &&
|
||||||
!traits::IsTypeOrDerived<ARG0, Source>::value,
|
!traits::IsTypeOrDerived<ARG0, Source>,
|
||||||
T>*
|
T>*
|
||||||
create(ARG0&& arg0, ARGS&&... args) {
|
create(ARG0&& arg0, ARGS&&... args) {
|
||||||
AssertNotMoved();
|
AssertNotMoved();
|
||||||
|
@ -346,8 +346,8 @@ class ProgramBuilder {
|
||||||
/// @param args the arguments to pass to the type constructor
|
/// @param args the arguments to pass to the type constructor
|
||||||
/// @returns the node pointer
|
/// @returns the node pointer
|
||||||
template <typename T, typename... ARGS>
|
template <typename T, typename... ARGS>
|
||||||
traits::EnableIf<traits::IsTypeOrDerived<T, sem::Node>::value &&
|
traits::EnableIf<traits::IsTypeOrDerived<T, sem::Node> &&
|
||||||
!traits::IsTypeOrDerived<T, sem::Type>::value,
|
!traits::IsTypeOrDerived<T, sem::Type>,
|
||||||
T>*
|
T>*
|
||||||
create(ARGS&&... args) {
|
create(ARGS&&... args) {
|
||||||
AssertNotMoved();
|
AssertNotMoved();
|
||||||
|
|
15
src/traits.h
15
src/traits.h
|
@ -86,13 +86,12 @@ using ParameterType = typename SignatureOfT<F>::template parameter<N>;
|
||||||
template <typename F>
|
template <typename F>
|
||||||
using ReturnType = typename SignatureOfT<F>::ret;
|
using ReturnType = typename SignatureOfT<F>::ret;
|
||||||
|
|
||||||
/// `IsTypeOrDerived<T, BASE>::value` is true iff `T` is of type `BASE`, or
|
/// IsTypeOrDerived<T, BASE> is true iff `T` is of type `BASE`, or derives from
|
||||||
/// derives from `BASE`.
|
/// `BASE`.
|
||||||
template <typename T, typename BASE>
|
template <typename T, typename BASE>
|
||||||
using IsTypeOrDerived =
|
static constexpr bool IsTypeOrDerived =
|
||||||
std::integral_constant<bool,
|
std::is_base_of<BASE, Decay<T>>::value ||
|
||||||
std::is_base_of<BASE, Decay<T>>::value ||
|
std::is_same<BASE, Decay<T>>::value;
|
||||||
std::is_same<BASE, Decay<T>>::value>;
|
|
||||||
|
|
||||||
/// If `CONDITION` is true then EnableIf resolves to type T, otherwise an
|
/// If `CONDITION` is true then EnableIf resolves to type T, otherwise an
|
||||||
/// invalid type.
|
/// 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
|
/// If `T` is of type `BASE`, or derives from `BASE`, then EnableIfIsType
|
||||||
/// resolves to type `T`, otherwise an invalid type.
|
/// resolves to type `T`, otherwise an invalid type.
|
||||||
template <typename T, typename BASE>
|
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
|
/// If `T` is not of type `BASE`, or does not derive from `BASE`, then
|
||||||
/// EnableIfIsNotType resolves to type `T`, otherwise an invalid type.
|
/// EnableIfIsNotType resolves to type `T`, otherwise an invalid type.
|
||||||
template <typename T, typename BASE>
|
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.
|
/// @returns the std::index_sequence with all the indices shifted by OFFSET.
|
||||||
template <std::size_t OFFSET, std::size_t... INDICES>
|
template <std::size_t OFFSET, std::size_t... INDICES>
|
||||||
|
|
Loading…
Reference in New Issue