mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-14 03:11:29 +00:00
Optimize tint::IsAnyOf<>() for many types
Split IsAnyOf() into log(n) stages, where each stage performs a hashcode check. Previously there was a single hash test across the bitwise-or of all the types being considered. If this passed, then each type would be tested with Is<T>() individually. With this change, the list of types will be recursively split into two, which each block hash-code checked. This is repeated until we reach fewer than 4 types to check, where the test decays to using Is<T>() for each type. Also renamed `combined_hashcode` to `full_hashcode`, and used the term CombinedHash for new helpers that bitwise-or the hashes from a number of types. Bug: tint:1383 Change-Id: Id056b9f7a9792430bd75ce554cb5fe73221ca4c7 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/78580 Reviewed-by: Antonio Maiorano <amaiorano@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Kokoro: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
e1699caf81
commit
b68e8aa658
@ -23,7 +23,7 @@ const TypeInfo detail::TypeInfoOf<CastableBase>::info{
|
|||||||
nullptr,
|
nullptr,
|
||||||
"CastableBase",
|
"CastableBase",
|
||||||
tint::TypeInfo::HashCodeOf<CastableBase>(),
|
tint::TypeInfo::HashCodeOf<CastableBase>(),
|
||||||
tint::TypeInfo::HashCodeOf<CastableBase>(),
|
tint::TypeInfo::FullHashCodeOf<CastableBase>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
153
src/castable.h
153
src/castable.h
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "src/traits.h"
|
#include "src/traits.h"
|
||||||
@ -61,7 +62,7 @@ struct TypeInfoOf;
|
|||||||
&tint::detail::TypeInfoOf<CLASS::TrueBase>::info, \
|
&tint::detail::TypeInfoOf<CLASS::TrueBase>::info, \
|
||||||
#CLASS, \
|
#CLASS, \
|
||||||
tint::TypeInfo::HashCodeOf<CLASS>(), \
|
tint::TypeInfo::HashCodeOf<CLASS>(), \
|
||||||
tint::TypeInfo::CombinedHashCodeOf<CLASS>(), \
|
tint::TypeInfo::FullHashCodeOf<CLASS>(), \
|
||||||
}; \
|
}; \
|
||||||
TINT_CASTABLE_POP_DISABLE_WARNINGS()
|
TINT_CASTABLE_POP_DISABLE_WARNINGS()
|
||||||
|
|
||||||
@ -86,17 +87,17 @@ struct TypeInfo {
|
|||||||
const char* name;
|
const char* name;
|
||||||
/// The type hash code
|
/// The type hash code
|
||||||
const HashCode hashcode;
|
const HashCode hashcode;
|
||||||
/// The type hash code or'd with the base class' combined hash code
|
/// The type hash code bitwise-or'd with all ancestor's hashcodes.
|
||||||
const HashCode combined_hashcode;
|
const HashCode full_hashcode;
|
||||||
|
|
||||||
/// @param type the test type info
|
/// @param type the test type info
|
||||||
/// @returns true if the class with this TypeInfo is of, or derives from the
|
/// @returns true if the class with this TypeInfo is of, or derives from the
|
||||||
/// class with the given TypeInfo.
|
/// class with the given TypeInfo.
|
||||||
inline bool Is(const tint::TypeInfo* type) const {
|
inline bool Is(const tint::TypeInfo* type) const {
|
||||||
// Optimization: Check whether the all the bits of the type's hashcode can
|
// Optimization: Check whether the all the bits of the type's hashcode can
|
||||||
// be found in the combined_hashcode. If a single bit is missing, then we
|
// be found in the full_hashcode. If a single bit is missing, then we
|
||||||
// can quickly tell that that this TypeInfo does not derive from `type`.
|
// can quickly tell that that this TypeInfo does not derive from `type`.
|
||||||
if ((combined_hashcode & type->hashcode) != type->hashcode) {
|
if ((full_hashcode & type->hashcode) != type->hashcode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +146,8 @@ 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,
|
||||||
|
"T is not Castable");
|
||||||
/// Use the compiler's "pretty" function name, which includes the template
|
/// Use the compiler's "pretty" function name, which includes the template
|
||||||
/// type, to obtain a unique hash value.
|
/// type, to obtain a unique hash value.
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@ -161,13 +164,75 @@ struct TypeInfo {
|
|||||||
/// @returns the hashcode of the given type, bitwise-or'd with the hashcodes
|
/// @returns the hashcode of the given type, bitwise-or'd with the hashcodes
|
||||||
/// of all base classes.
|
/// of all base classes.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr HashCode CombinedHashCodeOf() {
|
static constexpr HashCode FullHashCodeOf() {
|
||||||
if constexpr (std::is_same_v<T, CastableBase>) {
|
if constexpr (std::is_same_v<T, CastableBase>) {
|
||||||
return HashCodeOf<CastableBase>();
|
return HashCodeOf<CastableBase>();
|
||||||
} else {
|
} else {
|
||||||
return HashCodeOf<T>() | CombinedHashCodeOf<typename T::TrueBase>();
|
return HashCodeOf<T>() | FullHashCodeOf<typename T::TrueBase>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @returns the bitwise-or'd hashcodes of all the types of the tuple `TUPLE`.
|
||||||
|
/// @see HashCodeOf
|
||||||
|
template <typename TUPLE>
|
||||||
|
static constexpr HashCode CombinedHashCodeOfTuple() {
|
||||||
|
constexpr auto kCount = std::tuple_size_v<TUPLE>;
|
||||||
|
if constexpr (kCount == 0) {
|
||||||
|
return 0;
|
||||||
|
} else if constexpr (kCount == 1) {
|
||||||
|
return HashCodeOf<std::tuple_element_t<0, TUPLE>>();
|
||||||
|
} else {
|
||||||
|
constexpr auto kMid = kCount / 2;
|
||||||
|
return CombinedHashCodeOfTuple<traits::SliceTuple<0, kMid, TUPLE>>() |
|
||||||
|
CombinedHashCodeOfTuple<
|
||||||
|
traits::SliceTuple<kMid, kCount - kMid, TUPLE>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns the bitwise-or'd hashcodes of all the template parameter types.
|
||||||
|
/// @see HashCodeOf
|
||||||
|
template <typename... TYPES>
|
||||||
|
static constexpr HashCode CombinedHashCodeOf() {
|
||||||
|
return CombinedHashCodeOfTuple<std::tuple<TYPES...>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns true if this TypeInfo is of, or derives from any of the types in
|
||||||
|
/// `TUPLE`.
|
||||||
|
template <typename TUPLE>
|
||||||
|
inline bool IsAnyOfTuple() const {
|
||||||
|
constexpr auto kCount = std::tuple_size_v<TUPLE>;
|
||||||
|
if constexpr (kCount == 0) {
|
||||||
|
return false;
|
||||||
|
} else if constexpr (kCount == 1) {
|
||||||
|
return Is(&Of<std::tuple_element_t<0, TUPLE>>());
|
||||||
|
} else if constexpr (kCount == 2) {
|
||||||
|
return Is(&Of<std::tuple_element_t<0, TUPLE>>()) ||
|
||||||
|
Is(&Of<std::tuple_element_t<1, TUPLE>>());
|
||||||
|
} else if constexpr (kCount == 3) {
|
||||||
|
return Is(&Of<std::tuple_element_t<0, TUPLE>>()) ||
|
||||||
|
Is(&Of<std::tuple_element_t<1, TUPLE>>()) ||
|
||||||
|
Is(&Of<std::tuple_element_t<2, TUPLE>>());
|
||||||
|
} else {
|
||||||
|
// Optimization: Compare the object's hashcode to the bitwise-or of all
|
||||||
|
// the tested type's hashcodes. If there's no intersection of bits in
|
||||||
|
// the two masks, then we can guarantee that the type is not in `TO`.
|
||||||
|
if (full_hashcode & TypeInfo::CombinedHashCodeOfTuple<TUPLE>()) {
|
||||||
|
// Possibly one of the types in `TUPLE`.
|
||||||
|
// Split the search in two, and scan each block.
|
||||||
|
static constexpr auto kMid = kCount / 2;
|
||||||
|
return IsAnyOfTuple<traits::SliceTuple<0, kMid, TUPLE>>() ||
|
||||||
|
IsAnyOfTuple<traits::SliceTuple<kMid, kCount - kMid, TUPLE>>();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns true if this TypeInfo is of, or derives from any of the types in
|
||||||
|
/// `TYPES`.
|
||||||
|
template <typename... TYPES>
|
||||||
|
inline bool IsAnyOf() const {
|
||||||
|
return IsAnyOfTuple<std::tuple<TYPES...>>();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -181,10 +246,6 @@ struct TypeInfoOf {
|
|||||||
static const TypeInfo info;
|
static const TypeInfo info;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Forward declaration
|
|
||||||
template <typename TO_FIRST, typename... TO_REST>
|
|
||||||
struct IsAnyOf;
|
|
||||||
|
|
||||||
/// A placeholder structure used for template parameters that need a default
|
/// A placeholder structure used for template parameters that need a default
|
||||||
/// type, but can always be automatically inferred.
|
/// type, but can always be automatically inferred.
|
||||||
struct Infer;
|
struct Infer;
|
||||||
@ -204,39 +265,29 @@ inline bool Is(FROM* obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @returns true if `obj` is a valid pointer, and is of, or derives from the
|
/// @returns true if `obj` is a valid pointer, and is of, or derives from the
|
||||||
/// class `TO`, and pred(const TO*) returns true
|
/// type `TYPE`, and pred(const TYPE*) returns true
|
||||||
/// @param obj the object to test from
|
/// @param obj the object to test from
|
||||||
/// @param pred predicate function with signature `bool(const TO*)` called iff
|
/// @param pred predicate function with signature `bool(const TYPE*)` called iff
|
||||||
/// object is of, or derives from the class `TO`.
|
/// object is of, or derives from the class `TYPE`.
|
||||||
/// @see CastFlags
|
/// @see CastFlags
|
||||||
template <typename TO,
|
template <typename TYPE,
|
||||||
int FLAGS = 0,
|
int FLAGS = 0,
|
||||||
typename FROM = detail::Infer,
|
typename OBJ = detail::Infer,
|
||||||
typename Pred = detail::Infer>
|
typename Pred = detail::Infer>
|
||||||
inline bool Is(FROM* obj, Pred&& pred) {
|
inline bool Is(OBJ* obj, Pred&& pred) {
|
||||||
return Is<TO, FLAGS, FROM>(obj) &&
|
return Is<TYPE, FLAGS, OBJ>(obj) &&
|
||||||
pred(static_cast<std::add_const_t<TO>*>(obj));
|
pred(static_cast<std::add_const_t<TYPE>*>(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns true if `obj` is of, or derives from any of the `TO`
|
/// @returns true if `obj` is a valid pointer, and is of, or derives from any of
|
||||||
/// classes.
|
/// the types in `TYPES`.OBJ
|
||||||
/// @param obj the object to cast from
|
/// @param obj the object to query.
|
||||||
template <typename... TO, typename FROM>
|
template <typename... TYPES, typename OBJ>
|
||||||
inline bool IsAnyOf(FROM* obj) {
|
inline bool IsAnyOf(OBJ* obj) {
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Optimization: Compare the object's combined_hashcode to the bitwise-or of
|
return obj->TypeInfo().template IsAnyOf<TYPES...>();
|
||||||
// all the tested type's hashcodes. If there's no intersection of bits in the
|
|
||||||
// two masks, then we can guarantee that the type is not in `TO`.
|
|
||||||
using Helper = detail::IsAnyOf<TO...>;
|
|
||||||
auto* type = &obj->TypeInfo();
|
|
||||||
auto hashcode = type->combined_hashcode;
|
|
||||||
if ((Helper::kHashCodes & hashcode) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Possibly one of the types in `TO`. Continue to testing against each type.
|
|
||||||
return Helper::template Exec<FROM>(type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns obj dynamically cast to the type `TO` or `nullptr` if
|
/// @returns obj dynamically cast to the type `TO` or `nullptr` if
|
||||||
@ -402,38 +453,6 @@ class Castable : public BASE {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
/// Helper for Castable::IsAnyOf
|
|
||||||
template <typename TO_FIRST, typename... TO_REST>
|
|
||||||
struct IsAnyOf {
|
|
||||||
/// The bitwise-or of all typeinfo hashcodes
|
|
||||||
static constexpr auto kHashCodes =
|
|
||||||
TypeInfo::HashCodeOf<TO_FIRST>() | IsAnyOf<TO_REST...>::kHashCodes;
|
|
||||||
|
|
||||||
/// @param type castable object type to test
|
|
||||||
/// @returns true if `obj` is of, or derives from any of `[TO_FIRST,
|
|
||||||
/// ...TO_REST]`
|
|
||||||
template <typename FROM>
|
|
||||||
static bool Exec(const TypeInfo* type) {
|
|
||||||
return TypeInfo::Is<TO_FIRST, FROM>(type) ||
|
|
||||||
IsAnyOf<TO_REST...>::template Exec<FROM>(type);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/// Terminal specialization
|
|
||||||
template <typename TO>
|
|
||||||
struct IsAnyOf<TO> {
|
|
||||||
/// The bitwise-or of all typeinfo hashcodes
|
|
||||||
static constexpr auto kHashCodes = TypeInfo::HashCodeOf<TO>();
|
|
||||||
|
|
||||||
/// @param type castable object type to test
|
|
||||||
/// @returns true if `obj` is of, or derives from TO
|
|
||||||
template <typename FROM>
|
|
||||||
static bool Exec(const TypeInfo* type) {
|
|
||||||
return TypeInfo::Is<TO, FROM>(type);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
||||||
TINT_CASTABLE_POP_DISABLE_WARNINGS();
|
TINT_CASTABLE_POP_DISABLE_WARNINGS();
|
||||||
|
52
src/traits.h
52
src/traits.h
@ -16,9 +16,9 @@
|
|||||||
#define SRC_TRAITS_H_
|
#define SRC_TRAITS_H_
|
||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace tint {
|
namespace tint::traits {
|
||||||
namespace traits {
|
|
||||||
|
|
||||||
/// Convience type definition for std::decay<T>::type
|
/// Convience type definition for std::decay<T>::type
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -109,7 +109,51 @@ using EnableIfIsType = EnableIf<IsTypeOrDerived<T, BASE>::value, T>;
|
|||||||
template <typename T, typename BASE>
|
template <typename T, typename BASE>
|
||||||
using EnableIfIsNotType = EnableIf<!IsTypeOrDerived<T, BASE>::value, T>;
|
using EnableIfIsNotType = EnableIf<!IsTypeOrDerived<T, BASE>::value, T>;
|
||||||
|
|
||||||
} // namespace traits
|
/// @returns the std::index_sequence with all the indices shifted by OFFSET.
|
||||||
} // namespace tint
|
template <std::size_t OFFSET, std::size_t... INDICES>
|
||||||
|
constexpr auto Shift(std::index_sequence<INDICES...>) {
|
||||||
|
return std::integer_sequence<std::size_t, OFFSET + INDICES...>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns a std::integer_sequence with the integers `[OFFSET..OFFSET+COUNT)`
|
||||||
|
template <std::size_t OFFSET, std::size_t COUNT>
|
||||||
|
constexpr auto Range() {
|
||||||
|
return Shift<OFFSET>(std::make_index_sequence<COUNT>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
/// @returns the tuple `t` swizzled by `INDICES`
|
||||||
|
template <class TUPLE, std::size_t... INDICES>
|
||||||
|
constexpr auto Swizzle(TUPLE&& t, std::index_sequence<INDICES...>) {
|
||||||
|
return std::make_tuple(std::get<INDICES>(std::forward<TUPLE>(t))...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns a nullptr of the tuple type `TUPLE` swizzled by `INDICES`.
|
||||||
|
/// @note: This function is intended to be used in a `decltype()` expression,
|
||||||
|
/// and returns a pointer-to-tuple as the tuple may hold non-constructable
|
||||||
|
/// types.
|
||||||
|
template <class TUPLE, std::size_t... INDICES>
|
||||||
|
constexpr auto* SwizzlePtrTy(std::index_sequence<INDICES...>) {
|
||||||
|
using Swizzled = std::tuple<std::tuple_element_t<INDICES, TUPLE>...>;
|
||||||
|
return static_cast<Swizzled*>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/// @returns the slice of the tuple `t` with the tuple elements
|
||||||
|
/// `[OFFSET..OFFSET+COUNT)`
|
||||||
|
template <std::size_t OFFSET, std::size_t COUNT, typename TUPLE>
|
||||||
|
constexpr auto Slice(TUPLE&& t) {
|
||||||
|
return detail::Swizzle<TUPLE>(std::forward<TUPLE>(t), Range<OFFSET, COUNT>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves to the slice of the tuple `t` with the tuple elements
|
||||||
|
/// `[OFFSET..OFFSET+COUNT)`
|
||||||
|
template <std::size_t OFFSET, std::size_t COUNT, typename TUPLE>
|
||||||
|
using SliceTuple = std::remove_pointer_t<decltype(
|
||||||
|
detail::SwizzlePtrTy<TUPLE>(Range<OFFSET, COUNT>()))>;
|
||||||
|
|
||||||
|
} // namespace tint::traits
|
||||||
|
|
||||||
#endif // SRC_TRAITS_H_
|
#endif // SRC_TRAITS_H_
|
||||||
|
@ -28,13 +28,12 @@ void F3(int, S, float) {}
|
|||||||
TEST(ParamType, Function) {
|
TEST(ParamType, Function) {
|
||||||
F1({}); // Avoid unused method warning
|
F1({}); // Avoid unused method warning
|
||||||
F3(0, {}, 0); // Avoid unused method warning
|
F3(0, {}, 0); // Avoid unused method warning
|
||||||
static_assert(std::is_same<ParameterType<decltype(&F1), 0>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(&F1), 0>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&F3), 0>, int>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(&F3), 0>, int>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&F3), 1>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(&F3), 1>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&F3), 2>, float>::value,
|
static_assert(std::is_same_v<ParameterType<decltype(&F3), 2>, float>, "");
|
||||||
"");
|
static_assert(std::is_same_v<ReturnType<decltype(&F1)>, void>, "");
|
||||||
static_assert(std::is_same<ReturnType<decltype(&F1)>, void>::value, "");
|
static_assert(std::is_same_v<ReturnType<decltype(&F3)>, void>, "");
|
||||||
static_assert(std::is_same<ReturnType<decltype(&F3)>, void>::value, "");
|
|
||||||
static_assert(SignatureOfT<decltype(&F1)>::parameter_count == 1, "");
|
static_assert(SignatureOfT<decltype(&F1)>::parameter_count == 1, "");
|
||||||
static_assert(SignatureOfT<decltype(&F3)>::parameter_count == 3, "");
|
static_assert(SignatureOfT<decltype(&F3)>::parameter_count == 3, "");
|
||||||
}
|
}
|
||||||
@ -47,14 +46,12 @@ TEST(ParamType, Method) {
|
|||||||
};
|
};
|
||||||
C().F1({}); // Avoid unused method warning
|
C().F1({}); // Avoid unused method warning
|
||||||
C().F3(0, {}, 0); // Avoid unused method warning
|
C().F3(0, {}, 0); // Avoid unused method warning
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F1), 0>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 0>, int>, "");
|
||||||
"");
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 1>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 2>, float>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
|
static_assert(std::is_same_v<ReturnType<decltype(&C::F1)>, void>, "");
|
||||||
"");
|
static_assert(std::is_same_v<ReturnType<decltype(&C::F3)>, void>, "");
|
||||||
static_assert(std::is_same<ReturnType<decltype(&C::F1)>, void>::value, "");
|
|
||||||
static_assert(std::is_same<ReturnType<decltype(&C::F3)>, void>::value, "");
|
|
||||||
static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1, "");
|
static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1, "");
|
||||||
static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3, "");
|
static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3, "");
|
||||||
}
|
}
|
||||||
@ -67,14 +64,12 @@ TEST(ParamType, ConstMethod) {
|
|||||||
};
|
};
|
||||||
C().F1({}); // Avoid unused method warning
|
C().F1({}); // Avoid unused method warning
|
||||||
C().F3(0, {}, 0); // Avoid unused method warning
|
C().F3(0, {}, 0); // Avoid unused method warning
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F1), 0>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 0>, int>, "");
|
||||||
"");
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 1>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 2>, float>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
|
static_assert(std::is_same_v<ReturnType<decltype(&C::F1)>, void>, "");
|
||||||
"");
|
static_assert(std::is_same_v<ReturnType<decltype(&C::F3)>, void>, "");
|
||||||
static_assert(std::is_same<ReturnType<decltype(&C::F1)>, void>::value, "");
|
|
||||||
static_assert(std::is_same<ReturnType<decltype(&C::F3)>, void>::value, "");
|
|
||||||
static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1, "");
|
static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1, "");
|
||||||
static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3, "");
|
static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3, "");
|
||||||
}
|
}
|
||||||
@ -87,14 +82,12 @@ TEST(ParamType, StaticMethod) {
|
|||||||
};
|
};
|
||||||
C::F1({}); // Avoid unused method warning
|
C::F1({}); // Avoid unused method warning
|
||||||
C::F3(0, {}, 0); // Avoid unused method warning
|
C::F3(0, {}, 0); // Avoid unused method warning
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F1), 0>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 0>, int>, "");
|
||||||
"");
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 1>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 2>, float>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
|
static_assert(std::is_same_v<ReturnType<decltype(&C::F1)>, void>, "");
|
||||||
"");
|
static_assert(std::is_same_v<ReturnType<decltype(&C::F3)>, void>, "");
|
||||||
static_assert(std::is_same<ReturnType<decltype(&C::F1)>, void>::value, "");
|
|
||||||
static_assert(std::is_same<ReturnType<decltype(&C::F3)>, void>::value, "");
|
|
||||||
static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1, "");
|
static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1, "");
|
||||||
static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3, "");
|
static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3, "");
|
||||||
}
|
}
|
||||||
@ -102,12 +95,12 @@ TEST(ParamType, StaticMethod) {
|
|||||||
TEST(ParamType, FunctionLike) {
|
TEST(ParamType, FunctionLike) {
|
||||||
using F1 = std::function<void(S)>;
|
using F1 = std::function<void(S)>;
|
||||||
using F3 = std::function<void(int, S, float)>;
|
using F3 = std::function<void(int, S, float)>;
|
||||||
static_assert(std::is_same<ParameterType<F1, 0>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<F1, 0>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<F3, 0>, int>::value, "");
|
static_assert(std::is_same_v<ParameterType<F3, 0>, int>, "");
|
||||||
static_assert(std::is_same<ParameterType<F3, 1>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<F3, 1>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<F3, 2>, float>::value, "");
|
static_assert(std::is_same_v<ParameterType<F3, 2>, float>, "");
|
||||||
static_assert(std::is_same<ReturnType<F1>, void>::value, "");
|
static_assert(std::is_same_v<ReturnType<F1>, void>, "");
|
||||||
static_assert(std::is_same<ReturnType<F3>, void>::value, "");
|
static_assert(std::is_same_v<ReturnType<F3>, void>, "");
|
||||||
static_assert(SignatureOfT<F1>::parameter_count == 1, "");
|
static_assert(SignatureOfT<F1>::parameter_count == 1, "");
|
||||||
static_assert(SignatureOfT<F3>::parameter_count == 3, "");
|
static_assert(SignatureOfT<F3>::parameter_count == 3, "");
|
||||||
}
|
}
|
||||||
@ -115,15 +108,117 @@ TEST(ParamType, FunctionLike) {
|
|||||||
TEST(ParamType, Lambda) {
|
TEST(ParamType, Lambda) {
|
||||||
auto l1 = [](S) {};
|
auto l1 = [](S) {};
|
||||||
auto l3 = [](int, S, float) {};
|
auto l3 = [](int, S, float) {};
|
||||||
static_assert(std::is_same<ParameterType<decltype(l1), 0>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(l1), 0>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(l3), 0>, int>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(l3), 0>, int>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(l3), 1>, S>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(l3), 1>, S>, "");
|
||||||
static_assert(std::is_same<ParameterType<decltype(l3), 2>, float>::value, "");
|
static_assert(std::is_same_v<ParameterType<decltype(l3), 2>, float>, "");
|
||||||
static_assert(std::is_same<ReturnType<decltype(l1)>, void>::value, "");
|
static_assert(std::is_same_v<ReturnType<decltype(l1)>, void>, "");
|
||||||
static_assert(std::is_same<ReturnType<decltype(l3)>, void>::value, "");
|
static_assert(std::is_same_v<ReturnType<decltype(l3)>, void>, "");
|
||||||
static_assert(SignatureOfT<decltype(l1)>::parameter_count == 1, "");
|
static_assert(SignatureOfT<decltype(l1)>::parameter_count == 1, "");
|
||||||
static_assert(SignatureOfT<decltype(l3)>::parameter_count == 3, "");
|
static_assert(SignatureOfT<decltype(l3)>::parameter_count == 3, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Slice, Empty) {
|
||||||
|
auto sliced = Slice<0, 0>(std::make_tuple<>());
|
||||||
|
static_assert(std::tuple_size_v<decltype(sliced)> == 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Slice, SingleElementSliceEmpty) {
|
||||||
|
auto sliced = Slice<0, 0>(std::make_tuple<int>(1));
|
||||||
|
static_assert(std::tuple_size_v<decltype(sliced)> == 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Slice, SingleElementSliceFull) {
|
||||||
|
auto sliced = Slice<0, 1>(std::make_tuple<int>(1));
|
||||||
|
static_assert(std::tuple_size_v<decltype(sliced)> == 1, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, int>,
|
||||||
|
"");
|
||||||
|
EXPECT_EQ(std::get<0>(sliced), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Slice, MixedTupleSliceEmpty) {
|
||||||
|
auto sliced = Slice<1, 0>(std::make_tuple<int, bool, float>(1, true, 2.0f));
|
||||||
|
static_assert(std::tuple_size_v<decltype(sliced)> == 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Slice, MixedTupleSliceFull) {
|
||||||
|
auto sliced = Slice<0, 3>(std::make_tuple<int, bool, float>(1, true, 2.0f));
|
||||||
|
static_assert(std::tuple_size_v<decltype(sliced)> == 3, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, int>,
|
||||||
|
"");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<1, decltype(sliced)>, bool>,
|
||||||
|
"");
|
||||||
|
static_assert(
|
||||||
|
std::is_same_v<std::tuple_element_t<2, decltype(sliced)>, float>, "");
|
||||||
|
EXPECT_EQ(std::get<0>(sliced), 1);
|
||||||
|
EXPECT_EQ(std::get<1>(sliced), true);
|
||||||
|
EXPECT_EQ(std::get<2>(sliced), 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Slice, MixedTupleSliceLowPart) {
|
||||||
|
auto sliced = Slice<0, 2>(std::make_tuple<int, bool, float>(1, true, 2.0f));
|
||||||
|
static_assert(std::tuple_size_v<decltype(sliced)> == 2, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, int>,
|
||||||
|
"");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<1, decltype(sliced)>, bool>,
|
||||||
|
"");
|
||||||
|
EXPECT_EQ(std::get<0>(sliced), 1);
|
||||||
|
EXPECT_EQ(std::get<1>(sliced), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Slice, MixedTupleSliceHighPart) {
|
||||||
|
auto sliced = Slice<1, 2>(std::make_tuple<int, bool, float>(1, true, 2.0f));
|
||||||
|
static_assert(std::tuple_size_v<decltype(sliced)> == 2, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, bool>,
|
||||||
|
"");
|
||||||
|
static_assert(
|
||||||
|
std::is_same_v<std::tuple_element_t<1, decltype(sliced)>, float>, "");
|
||||||
|
EXPECT_EQ(std::get<0>(sliced), true);
|
||||||
|
EXPECT_EQ(std::get<1>(sliced), 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SliceTuple, Empty) {
|
||||||
|
using sliced = SliceTuple<0, 0, std::tuple<>>;
|
||||||
|
static_assert(std::tuple_size_v<sliced> == 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SliceTuple, SingleElementSliceEmpty) {
|
||||||
|
using sliced = SliceTuple<0, 0, std::tuple<int>>;
|
||||||
|
static_assert(std::tuple_size_v<sliced> == 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SliceTuple, SingleElementSliceFull) {
|
||||||
|
using sliced = SliceTuple<0, 1, std::tuple<int>>;
|
||||||
|
static_assert(std::tuple_size_v<sliced> == 1, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, int>, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SliceTuple, MixedTupleSliceEmpty) {
|
||||||
|
using sliced = SliceTuple<1, 0, std::tuple<int, bool, float>>;
|
||||||
|
static_assert(std::tuple_size_v<sliced> == 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SliceTuple, MixedTupleSliceFull) {
|
||||||
|
using sliced = SliceTuple<0, 3, std::tuple<int, bool, float>>;
|
||||||
|
static_assert(std::tuple_size_v<sliced> == 3, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, int>, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<1, sliced>, bool>, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<2, sliced>, float>, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SliceTuple, MixedTupleSliceLowPart) {
|
||||||
|
using sliced = SliceTuple<0, 2, std::tuple<int, bool, float>>;
|
||||||
|
static_assert(std::tuple_size_v<sliced> == 2, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, int>, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<1, sliced>, bool>, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SliceTuple, MixedTupleSliceHighPart) {
|
||||||
|
using sliced = SliceTuple<1, 2, std::tuple<int, bool, float>>;
|
||||||
|
static_assert(std::tuple_size_v<sliced> == 2, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, bool>, "");
|
||||||
|
static_assert(std::is_same_v<std::tuple_element_t<1, sliced>, float>, "");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace traits
|
} // namespace traits
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
Loading…
x
Reference in New Issue
Block a user