Browse Source

Added typetraits.h

Бранимир Караџић 3 years ago
parent
commit
274771cb46
5 changed files with 1401 additions and 21 deletions
  1. 1 8
      include/bx/bx.h
  2. 1 13
      include/bx/inline/bx.inl
  3. 462 0
      include/bx/inline/typetraits.inl
  4. 280 0
      include/bx/typetraits.h
  5. 657 0
      tests/typetraits_test.cpp

+ 1 - 8
include/bx/bx.h

@@ -17,6 +17,7 @@
 #include "constants.h"
 #include "macros.h"
 #include "debug.h"
+#include "typetraits.h"
 
 ///
 #define BX_COUNTOF(_x) sizeof(bx::CountOfRequireArrayArgumentT(_x) )
@@ -37,14 +38,6 @@
 
 namespace bx
 {
-	/// Returns true if type `Ty` is trivially copyable / POD type.
-	template<typename Ty>
-	constexpr bool isTriviallyCopyable();
-
-	/// Returns true if type `Ty` is signed type.
-	template<typename Ty>
-	constexpr bool isSigned();
-
 	/// Arithmetic type `Ty` limits.
 	template<typename Ty, bool SignT = isSigned<Ty>()>
 	struct LimitsT;

+ 1 - 13
include/bx/inline/bx.inl

@@ -27,18 +27,6 @@ namespace bx
 		return _x;
 	}
 
-	template<typename Ty>
-	inline constexpr bool isTriviallyCopyable()
-	{
-		return __is_trivially_copyable(Ty);
-	}
-
-	template<typename Ty>
-	constexpr bool isSigned()
-	{
-		return Ty(-1) < Ty(0);
-	}
-
 	template<typename Ty>
 	inline Ty* addressOf(Ty& _a)
 	{
@@ -74,7 +62,7 @@ namespace bx
 	template<typename Ty>
 	inline void swap(Ty& _a, Ty& _b)
 	{
-		Ty tmp = _a; _a = _b; _b = tmp;
+		Ty tmp = move(_a); _a = move(_b); _b = move(tmp);
 	}
 
 	template<typename Ty>

+ 462 - 0
include/bx/inline/typetraits.inl

@@ -0,0 +1,462 @@
+/*
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
+ */
+
+#ifndef BX_TYPETRAITS_H_HEADER_GUARD
+#	error "Must be included from bx/typetraits.h!"
+#endif // BX_TYPETRAITS_H_HEADER_GUARD
+
+namespace bx
+{
+	// Reference(s):
+	//
+	// - GCC type traits compiler intrisics
+	//   https://gcc.gnu.org/onlinedocs/gcc-11.1.0/gcc/Type-Traits.html
+	//
+	// - Clang type trait primitives
+	//   https://clang.llvm.org/docs/LanguageExtensions.html#type-trait-primitives
+
+	//---
+	template<typename Ty, Ty ValueT>
+	struct IntegralConstantT
+	{
+		using ValueType = Ty;
+		static constexpr Ty value = ValueT;
+	};
+
+	template<bool BoolT>
+	using BoolConstantT = IntegralConstantT<bool, BoolT>;
+	using FalseConstant = BoolConstantT<false>;
+	using TrueConstant  = BoolConstantT<true >;
+
+	//---
+	template<typename Ty> struct TypeIdentityT { using Type = Ty; };
+	template<typename Ty>  using TypeIdentityType = typename TypeIdentityT<Ty>::Type;
+
+	//---
+	template<bool BoolT, typename Ty, typename Uy> struct ConditionalT                { using type = Ty; };
+	template<            typename Ty, typename Uy> struct ConditionalT<false, Ty, Uy> { using type = Uy; };
+	template<bool BoolT, typename Ty, typename Uy>  using ConditionalType = typename ConditionalT<BoolT, Ty, Uy>::Type;
+
+	//---
+	template<bool BoolT, typename Ty = void> struct EnableIfT           {                  };
+	template<            typename Ty       > struct EnableIfT<true, Ty> { using type = Ty; };
+	template<bool BoolT, typename Ty       >  using EnableIfType = typename EnableIfT<BoolT, Ty>::Type;
+
+	//---
+	template<typename Ty> struct AddLvalueReferenceT                      { using Type = Ty&;                 };
+	template<typename Ty> struct AddLvalueReferenceT<Ty&>                 { using Type = Ty&;                 };
+	template<>            struct AddLvalueReferenceT<               void> { using Type =                void; };
+	template<>            struct AddLvalueReferenceT<const          void> { using Type = const          void; };
+	template<>            struct AddLvalueReferenceT<volatile       void> { using Type = volatile       void; };
+	template<>            struct AddLvalueReferenceT<const volatile void> { using Type = const volatile void; };
+	template<typename Ty>  using AddLvalueReferenceType = typename AddLvalueReferenceT<Ty>::Type;
+
+	//---
+	template<typename Ty> struct AddRvalueReferenceT                      { using Type = Ty&&;                };
+	template<typename Ty> struct AddRvalueReferenceT<Ty&>                 { using Type = Ty&;                 };
+	template<>            struct AddRvalueReferenceT<               void> { using Type =                void; };
+	template<>            struct AddRvalueReferenceT<const          void> { using Type = const          void; };
+	template<>            struct AddRvalueReferenceT<volatile       void> { using Type = volatile       void; };
+	template<>            struct AddRvalueReferenceT<const volatile void> { using Type = const volatile void; };
+	template<typename Ty>  using AddRvalueReferenceType = typename AddRvalueReferenceT<Ty>::Type;
+
+	//---
+	template<typename Ty> struct RemoveReferenceT       { using Type = Ty; };
+	template<typename Ty> struct RemoveReferenceT<Ty&>  { using Type = Ty; };
+	template<typename Ty> struct RemoveReferenceT<Ty&&> { using Type = Ty; };
+	template<typename Ty>  using RemoveReferenceType = typename RemoveReferenceT<Ty>::Type;
+
+	//---
+	template<typename Ty> struct AddPointerT { using Type = TypeIdentityType<RemoveReferenceType<Ty>*>; };
+	template<typename Ty>  using AddPointerType = typename AddPointerT<Ty>::Type;
+
+	//---
+	template<typename Ty> struct RemovePointerT                                    { using Type = Ty; };
+	template<typename Ty> struct RemovePointerT<               Ty*               > { using Type = Ty; };
+	template<typename Ty> struct RemovePointerT<         const Ty*               > { using Type = Ty; };
+	template<typename Ty> struct RemovePointerT<      volatile Ty*               > { using Type = Ty; };
+	template<typename Ty> struct RemovePointerT<const volatile Ty*               > { using Type = Ty; };
+	template<typename Ty> struct RemovePointerT<const volatile Ty* const         > { using Type = Ty; };
+	template<typename Ty> struct RemovePointerT<               Ty* const         > { using Type = Ty; };
+	template<typename Ty> struct RemovePointerT<               Ty*       volatile> { using Type = Ty; };
+	template<typename Ty> struct RemovePointerT<               Ty* const volatile> { using Type = Ty; };
+	template<typename Ty>  using RemovePointerType = typename RemovePointerT<Ty>::Type;
+
+	//---
+	template<typename Ty> struct AddCvT { using Type = const volatile Ty; };
+	template<typename Ty>  using AddCvType = typename AddCvT<Ty>::Type;
+
+	//---
+	template<typename Ty> struct RemoveCvT                    { using Type = Ty; };
+	template<typename Ty> struct RemoveCvT<const Ty>          { using Type = Ty; };
+	template<typename Ty> struct RemoveCvT<volatile Ty>       { using Type = Ty; };
+	template<typename Ty> struct RemoveCvT<const volatile Ty> { using Type = Ty; };
+	template<typename Ty>  using RemoveCvType = typename RemoveCvT<Ty>::Type;
+
+	//---
+	template<typename Ty> struct AddConstT { using Type = const Ty; };
+	template<typename Ty>  using AddConstType = typename AddConstT<Ty>::Type;
+
+	//---
+	template<typename Ty> struct RemoveConstT           { using Type = Ty; };
+	template<typename Ty> struct RemoveConstT<const Ty> { using Type = Ty; };
+	template<typename Ty>  using RemoveConstType = typename RemoveConstT<Ty>::Type;
+
+	//---
+	template<typename Ty> struct AddVolatileT { using Type = volatile Ty; };
+	template<typename Ty>  using AddVolatileType = typename AddVolatileT<Ty>::Type;
+
+	//---
+	template<typename Ty> struct RemoveVolatileT              { using Type = Ty; };
+	template<typename Ty> struct RemoveVolatileT<volatile Ty> { using Type = Ty; };
+	template<typename Ty>  using RemoveVolatileType = typename RemoveVolatileT<Ty>::Type;
+
+	//---
+
+	template<typename Ty>               struct IsBoundedArrayT            : FalseConstant {};
+	template<typename Ty, size_t SizeT> struct IsBoundedArrayT<Ty[SizeT]> :  TrueConstant {};
+
+	template<typename Ty>
+	inline constexpr bool isBoundedArray()
+	{
+		return IsBoundedArrayT<Ty>::value;
+	}
+
+	template<typename Ty> struct IsUnboundedArrayT       : FalseConstant {};
+	template<typename Ty> struct IsUnboundedArrayT<Ty[]> :  TrueConstant {};
+
+	template<typename Ty>
+	inline constexpr bool isUnboundedArray()
+	{
+		return IsUnboundedArrayT<Ty>::value;
+	}
+
+	template<typename Ty>
+	inline constexpr bool isArray()
+	{
+		return isBoundedArray<Ty>()
+			|| isUnboundedArray<Ty>()
+			;
+	}
+
+	template<typename Ty>
+	constexpr bool isEnum()
+	{
+		return __is_enum(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isUnion()
+	{
+		return __is_union(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isAbstract()
+	{
+		return __is_abstract(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isAggregate()
+	{
+		return __is_aggregate(Ty);
+	}
+
+	template<typename BaseT, typename DerivedT>
+	inline constexpr bool isBaseOf()
+	{
+		return __is_base_of(BaseT, DerivedT);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isPolymorphic()
+	{
+		return __is_polymorphic(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isDestructorVirtual()
+	{
+		return __has_virtual_destructor(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isClass()
+	{
+		return __is_class(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isFinal()
+	{
+		return __is_final(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isEmpty()
+	{
+		return __is_empty(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isStandardLayout()
+	{
+		return __is_standard_layout(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isTrivial()
+	{
+		return __is_trivial(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isPod()
+	{
+		return isStandardLayout<Ty>()
+			&& isTrivial<Ty>()
+			;
+	}
+
+	template<typename Ty, typename FromT>
+	inline constexpr bool isAssignable()
+	{
+		return __is_assignable(Ty, FromT);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isCopyAssignable()
+	{
+		return isAssignable<
+				  AddLvalueReferenceType<Ty>
+				, AddLvalueReferenceType<const Ty>
+				>();
+	}
+
+	template<typename Ty>
+	inline constexpr bool isMoveAssignable()
+	{
+		return isAssignable<
+				  AddLvalueReferenceType<Ty>
+				, AddRvalueReferenceType<Ty>
+				>();
+	}
+
+	template<typename Ty, typename FromT>
+	inline constexpr bool isTriviallyAssignable()
+	{
+		return __is_trivially_assignable(Ty, FromT);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isTriviallyCopyAssignable()
+	{
+		return isTriviallyAssignable<
+				  AddLvalueReferenceType<Ty>
+				, AddRvalueReferenceType<const Ty>
+				>();
+	}
+
+	template<typename Ty>
+	inline constexpr bool isTriviallyMoveAssignable()
+	{
+		return isTriviallyAssignable<
+				  AddLvalueReferenceType<Ty>
+				, AddRvalueReferenceType<Ty>
+				>();
+	}
+
+	template<typename Ty, typename... ArgsT>
+	inline constexpr bool isConstructible()
+	{
+		return __is_constructible(Ty, ArgsT...);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isCopyConstructible()
+	{
+		return isConstructible<Ty, AddLvalueReferenceType<Ty>>();
+	}
+
+	template<typename Ty>
+	inline constexpr bool isMoveConstructible()
+	{
+		return isConstructible<Ty>();
+	}
+
+	template<typename Ty, typename... ArgsT>
+	inline constexpr bool isTriviallyConstructible()
+	{
+		return __is_trivially_constructible(Ty, ArgsT...);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isTriviallyCopyConstructible()
+	{
+		return isTriviallyConstructible<Ty, AddLvalueReferenceType<Ty>>();
+	}
+
+	template<typename Ty>
+	inline constexpr bool isTriviallyMoveConstructible()
+	{
+		return isTriviallyConstructible<Ty, AddRvalueReferenceType<Ty>>();
+	}
+
+	template<typename Ty>
+	inline constexpr bool isTriviallyCopyable()
+	{
+		return __is_trivially_copyable(Ty);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isTriviallyDestructible()
+	{
+#if BX_COMPILER_GCC
+		return __has_trivial_destructor(Ty);
+#else
+		return __is_trivially_destructible(Ty);
+#endif // BX_COMPILER_GCC
+	}
+
+	template<typename Ty> struct IsConstT           : FalseConstant {};
+	template<typename Ty> struct IsConstT<const Ty> :  TrueConstant {};
+
+	template<typename Ty>
+	inline constexpr bool isConst()
+	{
+		return IsConstT<Ty>::value;
+	}
+
+	template<typename Ty> struct IsVolatileT              : FalseConstant {};
+	template<typename Ty> struct IsVolatileT<volatile Ty> :  TrueConstant {};
+
+	template<typename Ty>
+	inline constexpr bool isVolatile()
+	{
+		return IsVolatileT<Ty>::value;
+	}
+
+	template<typename Ty> struct IsLvalueReferenceT      : FalseConstant {};
+	template<typename Ty> struct IsLvalueReferenceT<Ty&> :  TrueConstant {};
+
+	template<typename Ty>
+	inline constexpr bool isLvalueReference()
+	{
+		return IsLvalueReferenceT<Ty>::value;
+	}
+
+	template<typename Ty> struct IsRvalueReferenceT       : FalseConstant {};
+	template<typename Ty> struct IsRvalueReferenceT<Ty&&> :  TrueConstant {};
+
+	template<typename Ty>
+	inline constexpr bool isRvalueReference()
+	{
+		return IsRvalueReferenceT<Ty>::value;
+	}
+
+	template<typename Ty>
+	inline constexpr bool isReference()
+	{
+		return isLvalueReference<Ty>()
+			|| isRvalueReference<Ty>()
+			;
+	}
+
+	template<typename Ty> struct IsPointerT                     : FalseConstant {};
+	template<typename Ty> struct IsPointerT<Ty*>                :  TrueConstant {};
+	template<typename Ty> struct IsPointerT<Ty* const>          :  TrueConstant {};
+	template<typename Ty> struct IsPointerT<Ty* volatile>       :  TrueConstant {};
+	template<typename Ty> struct IsPointerT<Ty* const volatile> :  TrueConstant {};
+
+	template<typename Ty>
+	inline constexpr bool isPointer()
+	{
+		return IsPointerT<Ty>::value;
+	}
+
+	template<typename Ty>
+	inline constexpr bool isSigned()
+	{
+		return Ty(-1) < Ty(0);
+	}
+
+	template<typename Ty>
+	inline constexpr bool isUnsigned()
+	{
+		return Ty(-1) > Ty(0);
+	}
+
+	template<typename Ty> struct IsIntegerT                     : FalseConstant {};
+	template<>            struct IsIntegerT<bool              > :  TrueConstant {};
+	template<>            struct IsIntegerT<char              > :  TrueConstant {};
+	template<>            struct IsIntegerT<char16_t          > :  TrueConstant {};
+	template<>            struct IsIntegerT<char32_t          > :  TrueConstant {};
+	template<>            struct IsIntegerT<wchar_t           > :  TrueConstant {};
+	template<>            struct IsIntegerT<  signed char     > :  TrueConstant {};
+	template<>            struct IsIntegerT<unsigned char     > :  TrueConstant {};
+	template<>            struct IsIntegerT<         short    > :  TrueConstant {};
+	template<>            struct IsIntegerT<unsigned short    > :  TrueConstant {};
+	template<>            struct IsIntegerT<         int      > :  TrueConstant {};
+	template<>            struct IsIntegerT<unsigned int      > :  TrueConstant {};
+	template<>            struct IsIntegerT<         long     > :  TrueConstant {};
+	template<>            struct IsIntegerT<unsigned long     > :  TrueConstant {};
+	template<>            struct IsIntegerT<         long long> :  TrueConstant {};
+	template<>            struct IsIntegerT<unsigned long long> :  TrueConstant {};
+
+	template<typename Ty>
+	inline constexpr bool isInteger()
+	{
+		return IsIntegerT<Ty>::value;
+	}
+
+	template<typename Ty> struct IsFloatingPointT              : FalseConstant {};
+	template<>            struct IsFloatingPointT<float      > :  TrueConstant {};
+	template<>            struct IsFloatingPointT<     double> :  TrueConstant {};
+	template<>            struct IsFloatingPointT<long double> :  TrueConstant {};
+
+	template<typename Ty>
+	inline constexpr bool isFloatingPoint()
+	{
+		return IsFloatingPointT<Ty>::value;
+	}
+
+	template<typename Ty>
+	inline constexpr bool isArithmetic()
+	{
+		return isInteger<Ty>()
+			|| isFloatingPoint<Ty>()
+			;
+	}
+
+	template<typename Ty, typename Uy> struct IsSameT         : FalseConstant {};
+	template<typename Ty>              struct IsSameT<Ty, Ty> :  TrueConstant {};
+
+	template<typename Ty, typename Uy>
+	inline constexpr bool isSame()
+	{
+		return IsSameT<Ty, Uy>::value;
+	}
+
+	template<typename Ty>
+	constexpr RemoveReferenceType<Ty>&& move(Ty&& _a)
+	{
+		return static_cast<RemoveReferenceType<Ty>&&>(_a);
+	}
+
+	template<typename Ty>
+	inline constexpr Ty&& forward(RemoveReferenceType<Ty>& _a)
+	{
+		return static_cast<Ty&&>(_a);
+	}
+
+	template<typename Ty>
+	inline constexpr Ty&& forward(RemoveReferenceType<Ty>&& _a)
+	{
+		BX_STATIC_ASSERT(!isLvalueReference<Ty>(), "Can not forward an Rvalue as an Lvalue.");
+		return static_cast<Ty&&>(_a);
+	}
+
+} // namespace bx

+ 280 - 0
include/bx/typetraits.h

@@ -0,0 +1,280 @@
+/*
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
+ */
+
+#ifndef BX_TYPETRAITS_H_HEADER_GUARD
+#define BX_TYPETRAITS_H_HEADER_GUARD
+
+namespace bx
+{
+	/// Returns true if type `Ty` is array type with known bound, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isBoundedArray();
+
+	/// Returns true if type `Ty` is array type with unknown bound, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isUnboundedArray();
+
+	/// Returns true if type `Ty` is array type (bounded, or unbounded array), otherwise returns false.
+	template<typename Ty>
+	constexpr bool isArray();
+
+	/// Returns true if type `Ty` is enumeration type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isEnum();
+
+	/// Returns true if type `Ty` is union type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isUnion();
+
+	/// Returns true if type `Ty` is non-union class type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isClass();
+
+	/// Returns true if type `Ty` is abstract class type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isAbstract();
+
+	/// Returns true if type `Ty` is aggregate class type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isAggregate();
+
+	/// Returns true if type `DerivedT` is derived from `BaseT` type, or if both are the same
+	/// non-union type, otherwise returns false.
+	template<typename BaseT, typename DerivedT>
+	constexpr bool isBaseOf();
+
+	/// Returns true if type `Ty` is polymorphic class (if it has virtual function table) type,
+	/// otherwise returns false.
+	template<typename Ty>
+	constexpr bool isPolymorphic();
+
+	/// Returns true if type `Ty` has virtual destructor, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isDestructorVirtual();
+
+	/// Returns true if type `Ty` is class type with final specifier, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isFinal();
+
+	/// Returns true if type `Ty` is non-union class type with no non-static
+	/// members (a.k.a. sizeof(Ty) is zero), otherwise returns false.
+	template<typename Ty>
+	constexpr bool isEmpty();
+
+	/// Returns true if type `Ty` is standard-layout type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isStandardLayout();
+
+	/// Returns true if type `Ty` is trivial type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isTrivial();
+
+	/// Returns true if type `Ty` is POD (standard-layout, and trivial type), otherwise returns false.
+	template<typename Ty>
+	constexpr bool isPod();
+
+	/// Returns true if type `FromT` can be assigned to type `Ty`, otherwise returns false.
+	template<typename Ty, typename FromT>
+	constexpr bool isAssignable();
+
+	/// Returns true if type `Ty` has copy assignment operator, otherwise returns false.
+	template<typename Ty, typename Uy>
+	constexpr bool isCopyAssignable();
+
+	/// Returns true if type `Ty` has move assignment operator, otherwise returns false.
+	template<typename Ty, typename Uy>
+	constexpr bool isMoveAssignable();
+
+	/// Returns true if type `FromT` can be trivially assigned to type `Ty`, otherwise returns false.
+	template<typename Ty, typename FromT>
+	constexpr bool isTriviallyAssignable();
+
+	/// Returns true if type `Ty` is trivially copy-assignable type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isTriviallyCopyAssignable();
+
+	/// Returns true if type `Ty` is trivially move-assignable type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isTriviallyMoveAssignable();
+
+	/// Returns true if type `Ty` is constructible when the specified argument types are used,
+	/// otherwise returns false.
+	template<typename Ty, typename... ArgsT>
+	constexpr bool isConstructible();
+
+	/// Returns true if type `Ty` has copy constructor, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isCopyConstructible();
+
+	/// Returns true if type `Ty` has move constructor, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isMoveConstructible();
+
+	/// Returns true if type `Ty` is trivially constructible when the specified argument types are used,
+	/// otherwise returns false.
+	template<typename T, typename... ArgsT>
+	constexpr bool isTriviallyConstructible();
+
+	/// Returns true if type `Ty` has trivial copy constructor, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isTriviallyCopyConstructible();
+
+	/// Returns true if type `Ty` has trivial move constructor, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isTriviallyMoveConstructible();
+
+	/// Returns true if type `Ty` is trivially copyable / POD type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isTriviallyCopyable();
+
+	/// Returns true if type `Ty` has trivial destructor, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isTriviallyDestructible();
+
+	/// Returns true if type `Ty` is const-qualified type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isConst();
+
+	/// Returns true if type `Ty` is volatile-qualified type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isVolatile();
+
+	/// Returns true if type `Ty` is an reference type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isReference();
+
+	/// Returns true if type `Ty` is an Lvalue reference type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isLvalueReference();
+
+	/// Returns true if type `Ty` is an Rvalue reference type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isRvalueReference();
+
+	/// Returns true if type `Ty` is an pointer type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isPointer();
+
+	/// Returns true if type `Ty` is signed integer or floating-point type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isSigned();
+
+	/// Returns true if type `Ty` is unsigned integer type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isUnsigned();
+
+	/// Returns true if type `Ty` is integer type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isInteger();
+
+	/// Returns true if type `Ty` is floating-point type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isFloatingPoint();
+
+	/// Returns true if type `Ty` is arithmetic type, otherwise returns false.
+	template<typename Ty>
+	constexpr bool isArithmetic();
+
+	/// Returns true if type `Ty` and type `Uy` are the same type, otherwise returns false.
+	template<typename Ty, typename Uy>
+	constexpr bool isSame();
+
+} // namespace bx
+
+#include "inline/typetraits.inl"
+
+namespace bx
+{
+	/// Compile-time constant of specified type `Ty` with specified value `ValueT`.
+	template<typename Ty, Ty ValueT>
+	struct IntegralConstantT;
+
+	/// Alias of IntegralConstantT<bool, bool ValueT>.
+	template<bool BoolT>
+	using BoolConstantT = IntegralConstantT<bool, BoolT>;
+
+	/// Alias of BoolConstantT<bool, false>.
+	using FalseConstant = BoolConstantT<false>;
+
+	/// Alias of BoolConstantT<bool, true>.
+	using TrueConstant = BoolConstantT<true>;
+
+	/// Provides the member `Type` that names `Ty`.
+	template<typename Ty>
+	using TypeIdentityType = typename TypeIdentityT<Ty>::Type;
+
+	/// Conditionally selects `Ty` if `BoolT` is true, otherwise selects `Uy` type.
+	template<bool BoolT, typename Ty, typename Uy>
+	using ConditionalType = typename ConditionalT<BoolT, Ty, Uy>::Type;
+
+	/// If `BoolT` condition is true it provides `Ty` as `Type`, otherwise `Type` is undefined.
+	template<bool BoolT, typename Ty>
+	using EnableIfType = typename EnableIfT<BoolT, Ty>::Type;
+
+	/// If `Ty` is an object type or a function type that has no cv- or ref- qualifier, provides
+	/// a member `Type` which is `Ty&`. If `Ty` is an Rvalue reference to some type `Uy`, then
+	/// type is `Uy&`, otherwise type is `Ty`.
+	template<typename Ty>
+	using AddLvalueReferenceType = typename AddLvalueReferenceT<Ty>::Type;
+
+	/// If `Ty` is an object type or a function type that has no cv- or ref- qualifier, provides
+	/// a member `Type` which is `Ty&&`, otherwise type is `Ty`.
+	template<typename Ty>
+	using AddRvalueReferenceType = typename AddRvalueReferenceT<Ty>::Type;
+
+	/// If the type `Ty` is a reference type, provides the member typedef `Type`
+	/// which is the type referred to by `Ty`, otherwise type is `Ty`.
+	template<typename Ty>
+	using RemoveReferenceType = typename RemoveReferenceT<Ty>::Type;
+
+	/// If the type `Ty` is a reference type, provides the member typedef `Type`
+	/// which is a pointer to the referred type.
+	template<typename Ty>
+	using AddPointerType = typename AddPointerT<Ty>::Type;
+
+	/// If the type `Ty` is a pointer type, provides the member typedef `Type`
+	/// which is the type pointed to by `Ty`, otherwise type is `Ty`.
+	template<typename Ty>
+	using RemovePointerType = typename RemovePointerT<Ty>::Type;
+
+	/// Adds both `const`, and `volatile` to type `Ty`.
+	template<typename Ty>
+	using AddCvType = typename AddCvT<Ty>::Type;
+
+	/// Removes the topmost `const`, or the topmost `volatile`, or both, from type `Ty` if present.
+	template<typename Ty>
+	using RemoveCvType = typename RemoveCvT<Ty>::Type;
+
+	/// Adds `const` to type `Ty`.
+	template<typename Ty>
+	using AddConstType = typename AddConstT<Ty>::Type;
+
+	/// Removes the topmost `const` from type `Ty` if present.
+	template<typename Ty>
+	using RemoveConstType = typename RemoveConstT<Ty>::Type;
+
+	/// Adds `volatile` to type `Ty`.
+	template<typename Ty>
+	using AddVolatileType = typename AddVolatileT<Ty>::Type;
+
+	/// Removes the topmost `volatile` from type `Ty` if present.
+	template<typename Ty>
+	using RemoveVolatileType = typename RemoveVolatileT<Ty>::Type;
+
+	/// Removes reference from type `Ty` if present.
+	template<typename Ty>
+	constexpr RemoveReferenceType<Ty>&& move(Ty&& _a);
+
+	/// Forwards Lvalues as either Lvalues or as Rvalues.
+	template<typename Ty>
+	constexpr Ty&& forward(RemoveReferenceType<Ty>& _type);
+
+	/// Forwards Rvalues as Rvalues and prohibits forwarding of Rvalues as Lvalues.
+	template<typename Ty>
+	constexpr Ty&& forward(RemoveReferenceT<Ty>&& _type);
+
+} // namespace bx
+
+#endif // BX_TYPETRAITS_H_HEADER_GUARD

+ 657 - 0
tests/typetraits_test.cpp

@@ -0,0 +1,657 @@
+/*
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
+ */
+
+#include "test.h"
+#include <bx/typetraits.h>
+
+struct TestClass                {                                                                        };
+struct TestClassFinal final     {                                                                        };
+struct TestClassMember          { int32_t x;                                                             };
+struct TestClassMemberPrivate   { int32_t x; private: int32_t y;                                         };
+struct TestClassStaticOnly      { static int32_t x;                                                      };
+struct TestClassCtor            {                 TestClassCtor (const TestClassCtor&) {}                };
+struct TestClassDefaultCtor     {          TestClassDefaultCtor (const TestClassDefaultCtor&) = default; };
+struct TestClassDefaultDtor     {         ~TestClassDefaultDtor () = default;                            };
+struct TestClassVirtualDtor     { virtual ~TestClassVirtualDtor () = default;                            };
+struct TestClassAbstractBase    { virtual ~TestClassAbstractBase() = 0;                                  };
+struct TestClassPolymorphic     { virtual int32_t x() { return 1389; }                                   };
+struct TestClassDerivedA        /*                                                                       */
+		: TestClass             {                                                                        };
+struct TestClassDerivedB        /*                                                                       */
+		: TestClassDerivedA     {                                                                        };
+struct TestClassDerivedX        /*                                                                       */
+		: TestClassVirtualDtor  {                                                                        };
+union  TestUnionEmpty           {                                                                        };
+union  TestUnion                { int32_t x; float y;                                                    };
+enum   TestEnumEmpty            {                                                                        };
+enum   TestEnum                 { Enum                                                                   };
+
+TEST_CASE("type-traits isReference", "")
+{
+	STATIC_REQUIRE(!bx::isReference<TestClass   >() );
+	STATIC_REQUIRE( bx::isReference<TestClass&  >() );
+	STATIC_REQUIRE( bx::isReference<TestClass&& >() );
+	STATIC_REQUIRE(!bx::isReference<long        >() );
+	STATIC_REQUIRE( bx::isReference<long&       >() );
+	STATIC_REQUIRE( bx::isReference<long&&      >() );
+	STATIC_REQUIRE(!bx::isReference<double*     >() );
+	STATIC_REQUIRE( bx::isReference<double*&    >() );
+	STATIC_REQUIRE( bx::isReference<double*&&   >() );;
+}
+
+TEST_CASE("type-traits isLvalueReference", "")
+{
+	STATIC_REQUIRE(!bx::isLvalueReference<TestClass   >() );
+	STATIC_REQUIRE( bx::isLvalueReference<TestClass&  >() );
+	STATIC_REQUIRE(!bx::isLvalueReference<TestClass&& >() );
+	STATIC_REQUIRE(!bx::isLvalueReference<long        >() );
+	STATIC_REQUIRE( bx::isLvalueReference<long&       >() );
+	STATIC_REQUIRE(!bx::isLvalueReference<long&&      >() );
+	STATIC_REQUIRE(!bx::isLvalueReference<double*     >() );
+	STATIC_REQUIRE( bx::isLvalueReference<double*&    >() );
+	STATIC_REQUIRE(!bx::isLvalueReference<double*&&   >() );;
+}
+
+TEST_CASE("type-traits isRvalueReference", "")
+{
+	STATIC_REQUIRE(!bx::isRvalueReference<TestClass   >() );
+	STATIC_REQUIRE(!bx::isRvalueReference<TestClass&  >() );
+	STATIC_REQUIRE( bx::isRvalueReference<TestClass&& >() );
+	STATIC_REQUIRE(!bx::isRvalueReference<long        >() );
+	STATIC_REQUIRE(!bx::isRvalueReference<long&       >() );
+	STATIC_REQUIRE( bx::isRvalueReference<long&&      >() );
+	STATIC_REQUIRE(!bx::isRvalueReference<double*     >() );
+	STATIC_REQUIRE(!bx::isRvalueReference<double*&    >() );
+	STATIC_REQUIRE( bx::isRvalueReference<double*&&   >() );;
+}
+
+TEST_CASE("type-traits isPointer", "")
+{
+	STATIC_REQUIRE(!bx::isPointer<TestClass                  >() );
+	STATIC_REQUIRE(!bx::isPointer<TestClass&                 >() );
+	STATIC_REQUIRE( bx::isPointer<TestClass*                 >() );
+	STATIC_REQUIRE( bx::isPointer<TestClass const * volatile >() );
+	STATIC_REQUIRE(!bx::isPointer<int32_t                    >() );
+	STATIC_REQUIRE( bx::isPointer<int32_t*                   >() );
+	STATIC_REQUIRE(!bx::isPointer<int32_t[1389]              >() );
+}
+
+TEST_CASE("type-traits AddLvalueReferenceT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::AddLvalueReferenceType<TestClass  >, TestClass& >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddLvalueReferenceType<TestClass& >, TestClass& >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddLvalueReferenceType<TestClass&&>, TestClass& >() );
+
+	STATIC_REQUIRE( bx::isLvalueReference<bx::AddLvalueReferenceType<TestClass>   >() );
+	STATIC_REQUIRE( bx::isLvalueReference<bx::AddLvalueReferenceType<TestClass&>  >() );
+	STATIC_REQUIRE( bx::isLvalueReference<bx::AddLvalueReferenceType<TestClass&&> >() );
+}
+
+TEST_CASE("type-traits AddRvalueReferenceT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::AddRvalueReferenceType<TestClass  >, TestClass&& >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddRvalueReferenceType<TestClass& >, TestClass&  >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddRvalueReferenceType<TestClass&&>, TestClass&& >() );
+
+	STATIC_REQUIRE( bx::isRvalueReference<bx::AddRvalueReferenceType<TestClass>   >() );
+	STATIC_REQUIRE(!bx::isRvalueReference<bx::AddRvalueReferenceType<TestClass&>  >() );
+	STATIC_REQUIRE( bx::isRvalueReference<bx::AddRvalueReferenceType<TestClass&&> >() );
+}
+
+TEST_CASE("type-traits RemoveReferenceT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::RemoveReferenceType<TestClass  >, TestClass >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveReferenceType<TestClass& >, TestClass >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveReferenceType<TestClass&&>, TestClass >() );
+
+	STATIC_REQUIRE(!bx::isReference<bx::RemoveReferenceType<TestClass>   >() );
+	STATIC_REQUIRE(!bx::isReference<bx::RemoveReferenceType<TestClass&>  >() );
+	STATIC_REQUIRE(!bx::isReference<bx::RemoveReferenceType<TestClass&&> >() );
+}
+
+TEST_CASE("type-traits AddPointerT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::AddPointerType<TestClass  >, TestClass*   >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddPointerType<TestClass* >, TestClass**  >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddPointerType<TestClass& >, TestClass*   >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddPointerType<TestClass**>, TestClass*** >() );
+
+	STATIC_REQUIRE( bx::isPointer<bx::AddPointerType<TestClass>   >() );
+	STATIC_REQUIRE( bx::isPointer<bx::AddPointerType<TestClass*>  >() );
+	STATIC_REQUIRE( bx::isPointer<bx::AddPointerType<TestClass&>  >() );
+	STATIC_REQUIRE( bx::isPointer<bx::AddPointerType<TestClass**> >() );
+}
+
+TEST_CASE("type-traits RemovePointerT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::RemovePointerType<TestClass  >, TestClass                        >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemovePointerType<TestClass* >, TestClass                        >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemovePointerType<TestClass**>, TestClass*                       >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemovePointerType<bx::RemovePointerType<TestClass**>>, TestClass >() );
+
+	STATIC_REQUIRE(!bx::isPointer<bx::RemovePointerType<TestClass>                          >() );
+	STATIC_REQUIRE(!bx::isPointer<bx::RemovePointerType<TestClass*>                         >() );
+	STATIC_REQUIRE( bx::isPointer<bx::RemovePointerType<TestClass**>                        >() );
+	STATIC_REQUIRE(!bx::isPointer<bx::RemovePointerType<bx::RemovePointerType<TestClass**>> >() );
+}
+
+TEST_CASE("type-traits AddConstT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::AddConstType<               TestClass >, const          TestClass        >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddConstType<const          TestClass >, const          TestClass        >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddConstType<      volatile TestClass >, const volatile TestClass        >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddConstType<const volatile TestClass >, const volatile TestClass        >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddConstType<const volatile TestClass*>, const volatile TestClass* const >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddConstType<TestClass* const volatile>, TestClass* const volatile       >() );
+}
+
+TEST_CASE("type-traits RemoveConstT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::RemoveConstType<               TestClass >,          TestClass >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveConstType<const          TestClass >,          TestClass >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveConstType<      volatile TestClass >, volatile TestClass >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveConstType<const volatile TestClass >, volatile TestClass >() );
+	STATIC_REQUIRE(!bx::isSame<bx::RemoveConstType<const volatile TestClass*>, volatile TestClass*>() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveConstType<TestClass* const volatile>, TestClass* volatile>() );
+}
+
+TEST_CASE("type-traits AddVolatileT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::AddVolatileType<               TestClass >,       volatile TestClass           >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddVolatileType<const          TestClass >, const volatile TestClass           >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddVolatileType<      volatile TestClass >,       volatile TestClass           >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddVolatileType<const volatile TestClass >, const volatile TestClass           >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddVolatileType<const volatile TestClass*>, const volatile TestClass* volatile >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddVolatileType<TestClass* const volatile>, TestClass* const          volatile >() );
+}
+
+TEST_CASE("type-traits RemoveVolatileT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::RemoveVolatileType<               TestClass >,       TestClass  >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveVolatileType<const          TestClass >, const TestClass  >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveVolatileType<      volatile TestClass >,       TestClass  >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveVolatileType<const volatile TestClass >, const TestClass  >() );
+	STATIC_REQUIRE(!bx::isSame<bx::RemoveVolatileType<const volatile TestClass*>, const TestClass* >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveVolatileType<TestClass* const volatile>, TestClass* const >() );
+}
+
+TEST_CASE("type-traits AddCvT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::AddCvType<               TestClass >, const volatile TestClass                 >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddCvType<const          TestClass >, const volatile TestClass                 >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddCvType<      volatile TestClass >, const volatile TestClass                 >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddCvType<const volatile TestClass >, const volatile TestClass                 >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddCvType<const volatile TestClass*>, const volatile TestClass* const volatile >() );
+	STATIC_REQUIRE( bx::isSame<bx::AddCvType<TestClass* const volatile>, TestClass* const volatile                >() );
+}
+
+TEST_CASE("type-traits RemoveCvT", "")
+{
+	STATIC_REQUIRE( bx::isSame<bx::RemoveCvType<               TestClass >, TestClass  >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveCvType<const          TestClass >, TestClass  >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveCvType<      volatile TestClass >, TestClass  >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveCvType<const volatile TestClass >, TestClass  >() );
+	STATIC_REQUIRE(!bx::isSame<bx::RemoveCvType<const volatile TestClass*>, TestClass* >() );
+	STATIC_REQUIRE( bx::isSame<bx::RemoveCvType<TestClass* const volatile>, TestClass* >() );
+}
+
+TEST_CASE("type-traits isTriviallyCopyable", "")
+{
+	STATIC_REQUIRE( bx::isTriviallyCopyable<int32_t              >() );
+	STATIC_REQUIRE( bx::isTriviallyCopyable<TestClass            >() );
+	STATIC_REQUIRE(!bx::isTriviallyCopyable<TestClassCtor        >() );
+	STATIC_REQUIRE( bx::isTriviallyCopyable<TestClassDefaultCtor >() );
+	STATIC_REQUIRE( bx::isTriviallyCopyable<TestClassDefaultDtor >() );
+	STATIC_REQUIRE(!bx::isTriviallyCopyable<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isTriviallyConstructible", "")
+{
+	STATIC_REQUIRE( bx::isTriviallyConstructible<int32_t              >() );
+	STATIC_REQUIRE( bx::isTriviallyConstructible<TestClass            >() );
+	STATIC_REQUIRE(!bx::isTriviallyConstructible<TestClassCtor        >() );
+	STATIC_REQUIRE(!bx::isTriviallyConstructible<TestClassDefaultCtor >() );
+	STATIC_REQUIRE( bx::isTriviallyConstructible<TestClassDefaultDtor >() );
+	STATIC_REQUIRE(!bx::isTriviallyConstructible<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isTriviallyDestructible", "")
+{
+	STATIC_REQUIRE( bx::isTriviallyDestructible<int32_t              >() );
+	STATIC_REQUIRE( bx::isTriviallyDestructible<TestClass            >() );
+	STATIC_REQUIRE( bx::isTriviallyDestructible<TestClassCtor        >() );
+	STATIC_REQUIRE( bx::isTriviallyDestructible<TestClassDefaultCtor >() );
+	STATIC_REQUIRE( bx::isTriviallyDestructible<TestClassDefaultDtor >() );
+	STATIC_REQUIRE(!bx::isTriviallyDestructible<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isSigned", "")
+{
+	STATIC_REQUIRE(!bx::isSigned<bool                   >() );
+	STATIC_REQUIRE( bx::isSigned<char                   >() );
+	STATIC_REQUIRE( bx::isSigned<signed char            >() );
+	STATIC_REQUIRE(!bx::isSigned<unsigned char          >() );
+	STATIC_REQUIRE( bx::isSigned<short                  >() );
+	STATIC_REQUIRE(!bx::isSigned<unsigned short         >() );
+	STATIC_REQUIRE( bx::isSigned<int                    >() );
+	STATIC_REQUIRE(!bx::isSigned<unsigned int           >() );
+	STATIC_REQUIRE( bx::isSigned<long                   >() );
+	STATIC_REQUIRE(!bx::isSigned<unsigned long          >() );
+	STATIC_REQUIRE( bx::isSigned<long long              >() );
+	STATIC_REQUIRE(!bx::isSigned<unsigned long long     >() );
+	STATIC_REQUIRE( bx::isSigned<long long int          >() );
+	STATIC_REQUIRE(!bx::isSigned<unsigned long long int >() );
+
+	STATIC_REQUIRE( bx::isSigned<int8_t                 >() );
+	STATIC_REQUIRE(!bx::isSigned<uint8_t                >() );
+	STATIC_REQUIRE( bx::isSigned<int16_t                >() );
+	STATIC_REQUIRE(!bx::isSigned<uint16_t               >() );
+	STATIC_REQUIRE( bx::isSigned<int32_t                >() );
+	STATIC_REQUIRE(!bx::isSigned<uint32_t               >() );
+	STATIC_REQUIRE( bx::isSigned<int64_t                >() );
+	STATIC_REQUIRE(!bx::isSigned<uint64_t               >() );
+	STATIC_REQUIRE( bx::isSigned<intmax_t               >() );
+	STATIC_REQUIRE(!bx::isSigned<uintmax_t              >() );
+	STATIC_REQUIRE(!bx::isSigned<uintptr_t              >() );
+	STATIC_REQUIRE( bx::isSigned<ptrdiff_t              >() );
+	STATIC_REQUIRE(!bx::isSigned<size_t                 >() );
+
+	STATIC_REQUIRE( bx::isSigned<float                  >() );
+	STATIC_REQUIRE( bx::isSigned<double                 >() );
+	STATIC_REQUIRE( bx::isSigned<long double            >() );
+}
+
+TEST_CASE("type-traits isUnsigned", "")
+{
+	STATIC_REQUIRE( bx::isUnsigned<bool                   >() );
+	STATIC_REQUIRE(!bx::isUnsigned<char                   >() );
+	STATIC_REQUIRE(!bx::isUnsigned<signed char            >() );
+	STATIC_REQUIRE( bx::isUnsigned<unsigned char          >() );
+	STATIC_REQUIRE(!bx::isUnsigned<short                  >() );
+	STATIC_REQUIRE( bx::isUnsigned<unsigned short         >() );
+	STATIC_REQUIRE(!bx::isUnsigned<int                    >() );
+	STATIC_REQUIRE( bx::isUnsigned<unsigned int           >() );
+	STATIC_REQUIRE(!bx::isUnsigned<long                   >() );
+	STATIC_REQUIRE( bx::isUnsigned<unsigned long          >() );
+	STATIC_REQUIRE(!bx::isUnsigned<long long              >() );
+	STATIC_REQUIRE( bx::isUnsigned<unsigned long long     >() );
+	STATIC_REQUIRE(!bx::isUnsigned<long long int          >() );
+	STATIC_REQUIRE( bx::isUnsigned<unsigned long long int >() );
+
+	STATIC_REQUIRE(!bx::isUnsigned<int8_t                 >() );
+	STATIC_REQUIRE( bx::isUnsigned<uint8_t                >() );
+	STATIC_REQUIRE(!bx::isUnsigned<int16_t                >() );
+	STATIC_REQUIRE( bx::isUnsigned<uint16_t               >() );
+	STATIC_REQUIRE(!bx::isUnsigned<int32_t                >() );
+	STATIC_REQUIRE( bx::isUnsigned<uint32_t               >() );
+	STATIC_REQUIRE(!bx::isUnsigned<int64_t                >() );
+	STATIC_REQUIRE( bx::isUnsigned<uint64_t               >() );
+	STATIC_REQUIRE(!bx::isUnsigned<intmax_t               >() );
+	STATIC_REQUIRE( bx::isUnsigned<uintmax_t              >() );
+	STATIC_REQUIRE( bx::isUnsigned<uintptr_t              >() );
+	STATIC_REQUIRE(!bx::isUnsigned<ptrdiff_t              >() );
+	STATIC_REQUIRE( bx::isUnsigned<size_t                 >() );
+
+	STATIC_REQUIRE(!bx::isUnsigned<float                  >() );
+	STATIC_REQUIRE(!bx::isUnsigned<double                 >() );
+	STATIC_REQUIRE(!bx::isUnsigned<long double            >() );
+}
+
+TEST_CASE("type-traits isInteger", "")
+{
+	STATIC_REQUIRE( bx::isInteger<bool                   >() );
+	STATIC_REQUIRE( bx::isInteger<char                   >() );
+	STATIC_REQUIRE( bx::isInteger<signed char            >() );
+	STATIC_REQUIRE( bx::isInteger<unsigned char          >() );
+	STATIC_REQUIRE( bx::isInteger<short                  >() );
+	STATIC_REQUIRE( bx::isInteger<unsigned short         >() );
+	STATIC_REQUIRE( bx::isInteger<int                    >() );
+	STATIC_REQUIRE( bx::isInteger<unsigned int           >() );
+	STATIC_REQUIRE( bx::isInteger<long                   >() );
+	STATIC_REQUIRE( bx::isInteger<unsigned long          >() );
+	STATIC_REQUIRE( bx::isInteger<long long              >() );
+	STATIC_REQUIRE( bx::isInteger<unsigned long long     >() );
+	STATIC_REQUIRE( bx::isInteger<long long int          >() );
+	STATIC_REQUIRE( bx::isInteger<unsigned long long int >() );
+
+	STATIC_REQUIRE( bx::isInteger<int8_t                 >() );
+	STATIC_REQUIRE( bx::isInteger<uint8_t                >() );
+	STATIC_REQUIRE( bx::isInteger<int16_t                >() );
+	STATIC_REQUIRE( bx::isInteger<uint16_t               >() );
+	STATIC_REQUIRE( bx::isInteger<int32_t                >() );
+	STATIC_REQUIRE( bx::isInteger<uint32_t               >() );
+	STATIC_REQUIRE( bx::isInteger<int64_t                >() );
+	STATIC_REQUIRE( bx::isInteger<uint64_t               >() );
+	STATIC_REQUIRE( bx::isInteger<intmax_t               >() );
+	STATIC_REQUIRE( bx::isInteger<uintmax_t              >() );
+	STATIC_REQUIRE( bx::isInteger<uintptr_t              >() );
+	STATIC_REQUIRE( bx::isInteger<ptrdiff_t              >() );
+	STATIC_REQUIRE( bx::isInteger<size_t                 >() );
+
+	STATIC_REQUIRE(!bx::isInteger<float                  >() );
+	STATIC_REQUIRE(!bx::isInteger<double                 >() );
+	STATIC_REQUIRE(!bx::isInteger<long double            >() );
+
+	STATIC_REQUIRE(!bx::isInteger<TestClass            >() );
+	STATIC_REQUIRE(!bx::isInteger<TestClassCtor        >() );
+	STATIC_REQUIRE(!bx::isInteger<TestClassDefaultCtor >() );
+	STATIC_REQUIRE(!bx::isInteger<TestClassDefaultDtor >() );
+	STATIC_REQUIRE(!bx::isInteger<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isFloatingPoint", "")
+{
+	STATIC_REQUIRE(!bx::isFloatingPoint<bool                   >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<char                   >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<signed char            >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<unsigned char          >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<short                  >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<unsigned short         >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<int                    >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<unsigned int           >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<long                   >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<unsigned long          >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<long long              >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<unsigned long long     >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<long long int          >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<unsigned long long int >() );
+
+	STATIC_REQUIRE(!bx::isFloatingPoint<int8_t                 >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<uint8_t                >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<int16_t                >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<uint16_t               >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<int32_t                >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<uint32_t               >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<int64_t                >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<uint64_t               >() );
+
+	STATIC_REQUIRE(!bx::isFloatingPoint<intmax_t               >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<uintmax_t              >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<uintptr_t              >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<ptrdiff_t              >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<size_t                 >() );
+
+	STATIC_REQUIRE( bx::isFloatingPoint<float                  >() );
+	STATIC_REQUIRE( bx::isFloatingPoint<double                 >() );
+	STATIC_REQUIRE( bx::isFloatingPoint<long double            >() );
+
+	STATIC_REQUIRE(!bx::isFloatingPoint<TestClass            >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<TestClassCtor        >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<TestClassDefaultCtor >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<TestClassDefaultDtor >() );
+	STATIC_REQUIRE(!bx::isFloatingPoint<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isArithmetic", "")
+{
+	STATIC_REQUIRE( bx::isArithmetic<bool                   >() );
+	STATIC_REQUIRE( bx::isArithmetic<char                   >() );
+	STATIC_REQUIRE( bx::isArithmetic<signed char            >() );
+	STATIC_REQUIRE( bx::isArithmetic<unsigned char          >() );
+	STATIC_REQUIRE( bx::isArithmetic<short                  >() );
+	STATIC_REQUIRE( bx::isArithmetic<unsigned short         >() );
+	STATIC_REQUIRE( bx::isArithmetic<int                    >() );
+	STATIC_REQUIRE( bx::isArithmetic<unsigned int           >() );
+	STATIC_REQUIRE( bx::isArithmetic<long                   >() );
+	STATIC_REQUIRE( bx::isArithmetic<unsigned long          >() );
+	STATIC_REQUIRE( bx::isArithmetic<long long              >() );
+	STATIC_REQUIRE( bx::isArithmetic<unsigned long long     >() );
+	STATIC_REQUIRE( bx::isArithmetic<long long int          >() );
+	STATIC_REQUIRE( bx::isArithmetic<unsigned long long int >() );
+
+	STATIC_REQUIRE( bx::isArithmetic<int8_t                 >() );
+	STATIC_REQUIRE( bx::isArithmetic<uint8_t                >() );
+	STATIC_REQUIRE( bx::isArithmetic<int16_t                >() );
+	STATIC_REQUIRE( bx::isArithmetic<uint16_t               >() );
+	STATIC_REQUIRE( bx::isArithmetic<int32_t                >() );
+	STATIC_REQUIRE( bx::isArithmetic<uint32_t               >() );
+	STATIC_REQUIRE( bx::isArithmetic<int64_t                >() );
+	STATIC_REQUIRE( bx::isArithmetic<uint64_t               >() );
+	STATIC_REQUIRE( bx::isArithmetic<intmax_t               >() );
+	STATIC_REQUIRE( bx::isArithmetic<uintmax_t              >() );
+	STATIC_REQUIRE( bx::isArithmetic<uintptr_t              >() );
+	STATIC_REQUIRE( bx::isArithmetic<ptrdiff_t              >() );
+	STATIC_REQUIRE( bx::isArithmetic<size_t                 >() );
+
+	STATIC_REQUIRE( bx::isArithmetic<float                  >() );
+	STATIC_REQUIRE( bx::isArithmetic<double                 >() );
+	STATIC_REQUIRE( bx::isArithmetic<long double            >() );
+
+	STATIC_REQUIRE(!bx::isArithmetic<TestClass            >() );
+	STATIC_REQUIRE(!bx::isArithmetic<TestClassCtor        >() );
+	STATIC_REQUIRE(!bx::isArithmetic<TestClassDefaultCtor >() );
+	STATIC_REQUIRE(!bx::isArithmetic<TestClassDefaultDtor >() );
+	STATIC_REQUIRE(!bx::isArithmetic<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isBoundedArray", "")
+{
+	STATIC_REQUIRE(!bx::isBoundedArray<TestClass       >() );
+	STATIC_REQUIRE(!bx::isBoundedArray<TestClass[]     >() );
+	STATIC_REQUIRE( bx::isBoundedArray<TestClass[1389] >() );
+	STATIC_REQUIRE(!bx::isBoundedArray<float           >() );
+	STATIC_REQUIRE(!bx::isBoundedArray<int             >() );
+	STATIC_REQUIRE(!bx::isBoundedArray<int[]           >() );
+	STATIC_REQUIRE( bx::isBoundedArray<int[1389]       >() );
+}
+
+TEST_CASE("type-traits isUnboundedArray", "")
+{
+	STATIC_REQUIRE(!bx::isUnboundedArray<TestClass       >() );
+	STATIC_REQUIRE( bx::isUnboundedArray<TestClass[]     >() );
+	STATIC_REQUIRE(!bx::isUnboundedArray<TestClass[1389] >() );
+	STATIC_REQUIRE(!bx::isUnboundedArray<float           >() );
+	STATIC_REQUIRE(!bx::isUnboundedArray<int32_t         >() );
+	STATIC_REQUIRE( bx::isUnboundedArray<int32_t[]       >() );
+	STATIC_REQUIRE(!bx::isUnboundedArray<int32_t[1389]   >() );
+}
+
+TEST_CASE("type-traits isArray", "")
+{
+	STATIC_REQUIRE(!bx::isArray<TestClass       >() );
+	STATIC_REQUIRE( bx::isArray<TestClass[]     >() );
+	STATIC_REQUIRE( bx::isArray<TestClass[1389] >() );
+	STATIC_REQUIRE(!bx::isArray<float           >() );
+	STATIC_REQUIRE(!bx::isArray<int32_t         >() );
+	STATIC_REQUIRE( bx::isArray<int32_t[]       >() );
+	STATIC_REQUIRE( bx::isArray<int32_t[1389]   >() );
+	STATIC_REQUIRE( bx::isArray<TestUnion[]     >() );
+}
+
+TEST_CASE("type-traits isEnum", "")
+{
+	STATIC_REQUIRE(!bx::isEnum<TestClass      >() );
+	STATIC_REQUIRE(!bx::isEnum<TestUnion      >() );
+	STATIC_REQUIRE(!bx::isEnum<TestUnionEmpty >() );
+	STATIC_REQUIRE(!bx::isEnum<TestUnion[]    >() );
+	STATIC_REQUIRE(!bx::isEnum<int32_t[]      >() );
+	STATIC_REQUIRE( bx::isEnum<TestEnumEmpty  >() );
+	STATIC_REQUIRE( bx::isEnum<TestEnum       >() );
+}
+
+TEST_CASE("type-traits isUnion", "")
+{
+	STATIC_REQUIRE(!bx::isUnion<TestClass      >() );
+	STATIC_REQUIRE( bx::isUnion<TestUnion      >() );
+	STATIC_REQUIRE( bx::isUnion<TestUnionEmpty >() );
+	STATIC_REQUIRE(!bx::isUnion<TestUnion[]    >() );
+	STATIC_REQUIRE(!bx::isUnion<int32_t[]      >() );
+	STATIC_REQUIRE(!bx::isUnion<TestEnumEmpty  >() );
+	STATIC_REQUIRE(!bx::isUnion<TestEnum       >() );
+}
+
+TEST_CASE("type-traits isClass", "")
+{
+	STATIC_REQUIRE( bx::isClass<TestClass              >() );
+	STATIC_REQUIRE( bx::isClass<TestClassFinal         >() );
+	STATIC_REQUIRE( bx::isClass<TestClassCtor          >() );
+	STATIC_REQUIRE( bx::isClass<TestClassMember        >() );
+	STATIC_REQUIRE( bx::isClass<TestClassMemberPrivate >() );
+	STATIC_REQUIRE( bx::isClass<TestClassStaticOnly    >() );
+	STATIC_REQUIRE( bx::isClass<TestClassDefaultCtor   >() );
+	STATIC_REQUIRE( bx::isClass<TestClassDefaultDtor   >() );
+	STATIC_REQUIRE( bx::isClass<TestClassVirtualDtor   >() );
+	STATIC_REQUIRE( bx::isClass<TestClassAbstractBase  >() );
+	STATIC_REQUIRE( bx::isClass<TestClassDerivedA      >() );
+	STATIC_REQUIRE( bx::isClass<TestClassDerivedB      >() );
+	STATIC_REQUIRE(!bx::isClass<TestUnion              >() );
+	STATIC_REQUIRE(!bx::isClass<TestUnion[]            >() );
+	STATIC_REQUIRE(!bx::isClass<int32_t[]              >() );
+}
+
+TEST_CASE("type-traits isFinal", "")
+{
+	STATIC_REQUIRE(!bx::isFinal<TestClass              >() );
+	STATIC_REQUIRE( bx::isFinal<TestClassFinal         >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassCtor          >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassMember        >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassMemberPrivate >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassStaticOnly    >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassDefaultCtor   >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassDefaultDtor   >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassVirtualDtor   >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassAbstractBase  >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassPolymorphic   >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassDerivedA      >() );
+	STATIC_REQUIRE(!bx::isFinal<TestClassDerivedB      >() );
+	STATIC_REQUIRE(!bx::isFinal<TestUnion              >() );
+	STATIC_REQUIRE(!bx::isFinal<TestUnionEmpty         >() );
+	STATIC_REQUIRE(!bx::isFinal<TestUnion[]            >() );
+	STATIC_REQUIRE(!bx::isFinal<int32_t[]              >() );
+}
+
+TEST_CASE("type-traits isEmpty", "")
+{
+	STATIC_REQUIRE( bx::isEmpty<TestClass             >() );
+	STATIC_REQUIRE( bx::isEmpty<TestClassFinal        >() );
+	STATIC_REQUIRE( bx::isEmpty<TestClassCtor         >() );
+	STATIC_REQUIRE( bx::isEmpty<TestClassDefaultCtor  >() );
+	STATIC_REQUIRE( bx::isEmpty<TestClassDefaultDtor  >() );
+	STATIC_REQUIRE(!bx::isEmpty<TestClassVirtualDtor  >() );
+	STATIC_REQUIRE(!bx::isEmpty<TestClassAbstractBase >() );
+	STATIC_REQUIRE(!bx::isEmpty<TestClassPolymorphic  >() );
+	STATIC_REQUIRE(!bx::isEmpty<TestUnion             >() );
+	STATIC_REQUIRE(!bx::isEmpty<TestUnionEmpty        >() );
+	STATIC_REQUIRE(!bx::isEmpty<TestUnion[]           >() );
+	STATIC_REQUIRE(!bx::isEmpty<int32_t[]             >() );
+}
+
+TEST_CASE("type-traits isStandardLayout", "")
+{
+	STATIC_REQUIRE( bx::isStandardLayout<TestClass              >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestClassFinal         >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestClassCtor          >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestClassMember        >() );
+	STATIC_REQUIRE(!bx::isStandardLayout<TestClassMemberPrivate >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestClassStaticOnly    >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestClassDefaultCtor   >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestClassDefaultDtor   >() );
+	STATIC_REQUIRE(!bx::isStandardLayout<TestClassVirtualDtor   >() );
+	STATIC_REQUIRE(!bx::isStandardLayout<TestClassAbstractBase  >() );
+	STATIC_REQUIRE(!bx::isStandardLayout<TestClassPolymorphic   >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestClassDerivedA      >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestClassDerivedB      >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestUnion              >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestUnionEmpty         >() );
+	STATIC_REQUIRE( bx::isStandardLayout<TestUnion[]            >() );
+	STATIC_REQUIRE( bx::isStandardLayout<int32_t[]              >() );
+}
+
+TEST_CASE("type-traits isTrivial", "")
+{
+	STATIC_REQUIRE( bx::isTrivial<TestClass              >() );
+	STATIC_REQUIRE( bx::isTrivial<TestClassFinal         >() );
+	STATIC_REQUIRE(!bx::isTrivial<TestClassCtor          >() );
+	STATIC_REQUIRE( bx::isTrivial<TestClassMember        >() );
+	STATIC_REQUIRE( bx::isTrivial<TestClassMemberPrivate >() );
+	STATIC_REQUIRE( bx::isTrivial<TestClassStaticOnly    >() );
+	STATIC_REQUIRE(!bx::isTrivial<TestClassDefaultCtor   >() );
+	STATIC_REQUIRE( bx::isTrivial<TestClassDefaultDtor   >() );
+	STATIC_REQUIRE(!bx::isTrivial<TestClassVirtualDtor   >() );
+	STATIC_REQUIRE(!bx::isTrivial<TestClassAbstractBase  >() );
+	STATIC_REQUIRE(!bx::isTrivial<TestClassPolymorphic   >() );
+	STATIC_REQUIRE( bx::isTrivial<TestClassDerivedA      >() );
+	STATIC_REQUIRE( bx::isTrivial<TestClassDerivedB      >() );
+	STATIC_REQUIRE( bx::isTrivial<TestUnion              >() );
+	STATIC_REQUIRE( bx::isTrivial<TestUnionEmpty         >() );
+	STATIC_REQUIRE( bx::isTrivial<TestUnion[]            >() );
+	STATIC_REQUIRE( bx::isTrivial<int32_t[]              >() );
+}
+
+TEST_CASE("type-traits isPod", "")
+{
+	STATIC_REQUIRE( bx::isPod<TestClass              >() );
+	STATIC_REQUIRE( bx::isPod<TestClassFinal         >() );
+	STATIC_REQUIRE(!bx::isPod<TestClassCtor          >() );
+	STATIC_REQUIRE( bx::isPod<TestClassMember        >() );
+	STATIC_REQUIRE(!bx::isPod<TestClassMemberPrivate >() );
+	STATIC_REQUIRE( bx::isPod<TestClassStaticOnly    >() );
+	STATIC_REQUIRE(!bx::isPod<TestClassDefaultCtor   >() );
+	STATIC_REQUIRE( bx::isPod<TestClassDefaultDtor   >() );
+	STATIC_REQUIRE(!bx::isPod<TestClassVirtualDtor   >() );
+	STATIC_REQUIRE(!bx::isPod<TestClassPolymorphic   >() );
+	STATIC_REQUIRE(!bx::isPod<TestClassAbstractBase  >() );
+	STATIC_REQUIRE( bx::isPod<TestClassDerivedA      >() );
+	STATIC_REQUIRE( bx::isPod<TestClassDerivedB      >() );
+	STATIC_REQUIRE( bx::isPod<TestUnion              >() );
+	STATIC_REQUIRE( bx::isPod<TestUnionEmpty         >() );
+	STATIC_REQUIRE( bx::isPod<TestUnion[]            >() );
+	STATIC_REQUIRE( bx::isPod<int32_t[]              >() );
+}
+
+TEST_CASE("type-traits isPolymorphic", "")
+{
+	STATIC_REQUIRE(!bx::isPolymorphic<TestClass              >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestClassFinal         >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestClassCtor          >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestClassMember        >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestClassMemberPrivate >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestClassStaticOnly    >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestClassDefaultCtor   >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestClassDefaultDtor   >() );
+	STATIC_REQUIRE( bx::isPolymorphic<TestClassVirtualDtor   >() );
+	STATIC_REQUIRE( bx::isPolymorphic<TestClassAbstractBase  >() );
+	STATIC_REQUIRE( bx::isPolymorphic<TestClassPolymorphic   >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestClassDerivedA      >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestClassDerivedB      >() );
+	STATIC_REQUIRE( bx::isPolymorphic<TestClassDerivedX      >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestUnion              >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestUnionEmpty         >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<TestUnion[]            >() );
+	STATIC_REQUIRE(!bx::isPolymorphic<int32_t[]              >() );
+}
+
+TEST_CASE("type-traits isDestructorVirtual", "")
+{
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClass              >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassFinal         >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassCtor          >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassMember        >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassMemberPrivate >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassStaticOnly    >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassDefaultCtor   >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassDefaultDtor   >() );
+	STATIC_REQUIRE( bx::isDestructorVirtual<TestClassVirtualDtor   >() );
+	STATIC_REQUIRE( bx::isDestructorVirtual<TestClassAbstractBase  >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassPolymorphic   >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassDerivedA      >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassDerivedB      >() );
+	STATIC_REQUIRE( bx::isDestructorVirtual<TestClassDerivedX      >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestUnion              >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestUnionEmpty         >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<TestUnion[]            >() );
+	STATIC_REQUIRE(!bx::isDestructorVirtual<int32_t[]              >() );
+}
+
+TEST_CASE("type-traits isBaseOf", "")
+{
+	STATIC_REQUIRE( bx::isBaseOf<TestClass,         TestClass         >() );
+	STATIC_REQUIRE( bx::isBaseOf<TestClass,         TestClassDerivedA >() );
+	STATIC_REQUIRE( bx::isBaseOf<TestClass,         TestClassDerivedB >() );
+	STATIC_REQUIRE(!bx::isBaseOf<TestClass,         TestClassFinal    >() );
+	STATIC_REQUIRE(!bx::isBaseOf<TestClassDerivedB, TestClassDerivedA >() );
+	STATIC_REQUIRE(!bx::isBaseOf<TestClassDerivedB, TestClassDerivedX >() );
+	STATIC_REQUIRE(!bx::isBaseOf<int32_t,           int32_t           >() );
+}