#include "typetraits.h" #include #include #include namespace { enum ETestEnum { }; class TPodClass { }; class TNonPodClass { TNonPodClass() { } }; class TEmptyClass { void operator()() const { } }; class TAnotherEmptyClass { }; class TEmptyDerivedClass: public TEmptyClass { }; class TEmptyMultiDerivedClass: public TEmptyDerivedClass, public TAnotherEmptyClass { /* Not empty under MSVC. * MSVC's EBCO implementation can handle only one empty base class. */ }; struct TNonEmptyClass { TEmptyClass member; }; class TNonEmptyDerivedClass: public TNonEmptyClass { }; class TStdLayoutClass1: public TEmptyClass { public: int Value1; int Value2; }; class TStdLayoutClass2: public TNonEmptyClass { }; class TNonStdLayoutClass1 { public: int Value1; protected: int Value2; }; class TNonStdLayoutClass2 { public: virtual void Func() { } }; class TNonStdLayoutClass3: public TNonStdLayoutClass2 { }; class TNonStdLayoutClass4: public TEmptyClass { public: TEmptyClass Base; }; } // namespace #define ASSERT_SAME_TYPE(x, y) \ { \ const bool x_ = std::is_same::value; \ UNIT_ASSERT_C(x_, #x " != " #y); \ } Y_UNIT_TEST_SUITE(TTypeTraitsTest) { Y_UNIT_TEST(TestIsSame) { UNIT_ASSERT((std::is_same::value)); UNIT_ASSERT(!(std::is_same::value)); } Y_UNIT_TEST(TestRemoveReference) { ASSERT_SAME_TYPE(std::remove_reference_t, int); ASSERT_SAME_TYPE(std::remove_reference_t, const int); ASSERT_SAME_TYPE(std::remove_reference_t, int); ASSERT_SAME_TYPE(std::remove_reference_t, const int); ASSERT_SAME_TYPE(std::remove_reference_t, int); ASSERT_SAME_TYPE(std::remove_reference_t, const int); class TIncompleteType; ASSERT_SAME_TYPE(std::remove_reference_t, TIncompleteType); } Y_UNIT_TEST(TestRemoveConst) { ASSERT_SAME_TYPE(std::remove_const_t, int); } Y_UNIT_TEST(TestRemoveVolatile) { ASSERT_SAME_TYPE(std::remove_volatile_t, int); } Y_UNIT_TEST(TestRemoveCV) { ASSERT_SAME_TYPE(std::remove_cv_t, int); } Y_UNIT_TEST(TestAddCV) { ASSERT_SAME_TYPE(std::add_cv_t, const volatile int); } Y_UNIT_TEST(TestClass) { UNIT_ASSERT(std::is_class::value); UNIT_ASSERT(!std::is_class::value); UNIT_ASSERT(!std::is_class::value); UNIT_ASSERT(!std::is_class::value); } template inline void TestArithmeticType() { UNIT_ASSERT(std::is_arithmetic::value); UNIT_ASSERT(std::is_arithmetic::value); UNIT_ASSERT(std::is_arithmetic::value); UNIT_ASSERT(std::is_arithmetic::value); UNIT_ASSERT(!std::is_arithmetic::value); UNIT_ASSERT(!std::is_arithmetic::value); UNIT_ASSERT(!std::is_arithmetic::value); bool a; a = std::is_same::TFuncParam, T>::value; UNIT_ASSERT(a); a = std::is_same::TFuncParam, const volatile T>::value; UNIT_ASSERT(a); } template inline void TestUnsignedIntType() { UNIT_ASSERT(std::is_unsigned::value); UNIT_ASSERT(std::is_unsigned::value); UNIT_ASSERT(std::is_unsigned::value); UNIT_ASSERT(std::is_unsigned::value); UNIT_ASSERT(!std::is_unsigned::value); UNIT_ASSERT(!std::is_unsigned::value); UNIT_ASSERT(!std::is_unsigned::value); enum ETypedEnum: T {}; UNIT_ASSERT(!std::is_unsigned::value); } template inline void TestSignedIntType() { UNIT_ASSERT(std::is_signed::value); UNIT_ASSERT(std::is_signed::value); UNIT_ASSERT(std::is_signed::value); UNIT_ASSERT(std::is_signed::value); UNIT_ASSERT(!std::is_signed::value); UNIT_ASSERT(!std::is_signed::value); UNIT_ASSERT(!std::is_signed::value); enum ETypedEnum: T {}; UNIT_ASSERT(!std::is_signed::value); } Y_UNIT_TEST(TestBool) { TestArithmeticType(); TestUnsignedIntType(); } Y_UNIT_TEST(TestUnsignedChar) { TestArithmeticType(); TestUnsignedIntType(); } Y_UNIT_TEST(TestSizeT) { TestArithmeticType(); TestUnsignedIntType(); } Y_UNIT_TEST(TestInt) { TestArithmeticType(); TestSignedIntType(); } Y_UNIT_TEST(TestDouble) { TestArithmeticType(); } Y_UNIT_TEST(TestLongDouble) { TestArithmeticType(); } Y_UNIT_TEST(TestAddRValueReference) { ASSERT_SAME_TYPE(std::add_rvalue_reference_t, int&&); ASSERT_SAME_TYPE(std::add_rvalue_reference_t, int const&); ASSERT_SAME_TYPE(std::add_rvalue_reference_t, int*&&); ASSERT_SAME_TYPE(std::add_rvalue_reference_t, int*&); ASSERT_SAME_TYPE(std::add_rvalue_reference_t, int&&); ASSERT_SAME_TYPE(std::add_rvalue_reference_t, void); } Y_UNIT_TEST(TestIsEmpty) { UNIT_ASSERT(std::is_empty::value); UNIT_ASSERT(std::is_empty::value); UNIT_ASSERT(std::is_empty::value); #ifdef _MSC_VER UNIT_ASSERT(!std::is_empty::value); #else UNIT_ASSERT(std::is_empty::value); #endif UNIT_ASSERT(!std::is_empty::value); UNIT_ASSERT(!std::is_empty::value); } Y_UNIT_TEST(TestIsStandardLayout) { UNIT_ASSERT(std::is_standard_layout::value); UNIT_ASSERT(std::is_standard_layout::value); UNIT_ASSERT(!std::is_standard_layout::value); UNIT_ASSERT(!std::is_standard_layout::value); UNIT_ASSERT(!std::is_standard_layout::value); UNIT_ASSERT(!std::is_standard_layout::value); } template using TTrySum = decltype(std::declval() + std::declval()); Y_UNIT_TEST(TestIsTriviallyCopyable) { struct TPod { int value; }; struct TNontriviallyCopyAssignable { TNontriviallyCopyAssignable(const TNontriviallyCopyAssignable&) = default; TNontriviallyCopyAssignable& operator=(const TNontriviallyCopyAssignable&); }; struct TNonTriviallyCopyConstructible { TNonTriviallyCopyConstructible(const TNonTriviallyCopyConstructible&); TNonTriviallyCopyConstructible& operator=(const TNonTriviallyCopyConstructible&) = default; }; struct TNonTriviallyDestructible { TNonTriviallyDestructible(const TNonTriviallyDestructible&) = default; TNonTriviallyDestructible& operator=(const TNonTriviallyDestructible&) = default; ~TNonTriviallyDestructible(); }; UNIT_ASSERT(std::is_trivially_copyable::value); UNIT_ASSERT(std::is_trivially_copyable::value); UNIT_ASSERT(!std::is_trivially_copyable::value); UNIT_ASSERT(!std::is_trivially_copyable::value); UNIT_ASSERT(!std::is_trivially_copyable::value); } } // Y_UNIT_TEST_SUITE(TTypeTraitsTest) namespace { template struct TTypeTraitsExpected; template <> struct TTypeTraitsExpected { enum { IsIntegral = false }; enum { IsArithmetic = false }; enum { IsPod = true }; enum { IsVolatile = false }; enum { IsConstant = false }; enum { IsPointer = false }; enum { IsReference = false }; enum { IsLvalueReference = false }; enum { IsRvalueReference = false }; enum { IsArray = false }; enum { IsClassType = false }; enum { IsVoid = true }; enum { IsEnum = false }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsIntegral = true }; enum { IsArithmetic = true }; enum { IsVoid = false }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsIntegral = false }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsConstant = true }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsVolatile = true }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsIntegral = false }; enum { IsArithmetic = false }; enum { IsEnum = true }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsClassType = true }; enum { IsVoid = false }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsPod = false }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsClassType = false }; enum { IsReference = true }; enum { IsLvalueReference = true }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsClassType = false }; enum { IsReference = true }; enum { IsRvalueReference = true }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsIntegral = false }; enum { IsArithmetic = false }; enum { IsPointer = true }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsPointer = false }; enum { IsReference = true }; enum { IsLvalueReference = true }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsPointer = false }; enum { IsReference = true }; enum { IsRvalueReference = true }; }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { }; template <> struct TTypeTraitsExpected: public TTypeTraitsExpected { enum { IsIntegral = false }; enum { IsArithmetic = false }; enum { IsArray = true }; }; } // namespace #define UNIT_ASSERT_EQUAL_ENUM(expected, actual) UNIT_ASSERT_VALUES_EQUAL((bool)(expected), (bool)(actual)) Y_UNIT_TEST_SUITE(TTypeTraitsTestNg) { template void TestImpl() { // UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsPod, TTypeTraits::IsPod); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsVoid, std::is_void::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsEnum, std::is_enum::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsIntegral, std::is_integral::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsArithmetic, std::is_arithmetic::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsVolatile, std::is_volatile::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsConstant, std::is_const::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsPointer, std::is_pointer::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsReference, std::is_reference::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsLvalueReference, std::is_lvalue_reference::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsRvalueReference, std::is_rvalue_reference::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsArray, std::is_array::value); UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected::IsClassType, std::is_class::value); } #define TYPE_TEST(name, type) \ Y_UNIT_TEST(name) { \ TestImpl(); \ } TYPE_TEST(Void, void) TYPE_TEST(Int, int) TYPE_TEST(Float, float) TYPE_TEST(LongDouble, long double) TYPE_TEST(SizeT, size_t) TYPE_TEST(VolatileInt, volatile int) TYPE_TEST(ConstInt, const int) TYPE_TEST(Enum, ETestEnum) TYPE_TEST(FloatPointer, float*) TYPE_TEST(FloatReference, float&) TYPE_TEST(FloatConstReference, const float&) TYPE_TEST(FloatArray, float[17]) TYPE_TEST(PodClass, TPodClass) TYPE_TEST(NonPodClass, TNonPodClass) TYPE_TEST(NonPodClassReference, TNonPodClass&) TYPE_TEST(NonPodClassConstReference, const TNonPodClass&) } // Y_UNIT_TEST_SUITE(TTypeTraitsTestNg) enum E4 { X }; enum class E64: ui64 { X }; enum class E8: ui8 { X }; // test for std::underlying_type_t static_assert(sizeof(std::underlying_type_t) == sizeof(int), ""); static_assert(sizeof(std::underlying_type_t) == sizeof(ui64), ""); static_assert(sizeof(std::underlying_type_t) == sizeof(ui8), ""); // tests for TFixedWidthUnsignedInt static_assert(std::is_same>::value, ""); static_assert(std::is_same>::value, ""); static_assert(std::is_same>::value, ""); static_assert(std::is_same>::value, ""); // tests for TFixedWidthSignedInt static_assert(std::is_same>::value, ""); static_assert(std::is_same>::value, ""); static_assert(std::is_same>::value, ""); static_assert(std::is_same>::value, ""); // test for TIsSpecializationOf static_assert(TIsSpecializationOf>::value, ""); static_assert(TIsSpecializationOf>::value, ""); static_assert(!TIsSpecializationOf>::value, ""); static_assert(!TIsSpecializationOf>::value, ""); // test for TIsTemplateBaseOf static_assert(TIsTemplateBaseOf>::value); static_assert(TIsTemplateBaseOf>::value); static_assert(TIsTemplateBaseOf::value); static_assert(TIsTemplateBaseOf>::value); static_assert(!TIsTemplateBaseOf>::value); static_assert(TIsTemplateBaseOf::value); static_assert(TIsTemplateBaseOf::value); static_assert(TIsTemplateBaseOf::value); // test for TIsIterable static_assert(TIsIterable>::value, ""); static_assert(!TIsIterable::value, ""); static_assert(TIsIterable::value, ""); // test for TDependentFalse static_assert(TDependentFalse == false); static_assert(TDependentFalse == false); static_assert(TValueDependentFalse<0x1000> == false);