/* Type traits for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OSTD_TYPE_TRAITS_HH #define OSTD_TYPE_TRAITS_HH #include #include "ostd/types.hh" namespace ostd { /* forward declarations */ namespace detail { template struct RemoveCvBase; template struct AddLr; template struct AddRr; template struct AddConstBase; template struct RemoveReferenceBase; template struct RemoveAllExtentsBase; template struct CommonTypeBase; } template using RemoveCv = typename detail::RemoveCvBase::Type; template using AddLvalueReference = typename detail::AddLr::Type; template using AddRvalueReference = typename detail::AddRr::Type; template using AddConst = typename detail::AddConstBase::Type; template using RemoveReference = typename detail::RemoveReferenceBase::Type; template using RemoveAllExtents = typename detail::RemoveAllExtentsBase::Type; namespace detail { template AddRvalueReference declval_in(); } /* integral constant */ template struct Constant { static constexpr T value = val; using Value = T; using Type = Constant; constexpr operator Value() const { return value; } constexpr Value operator()() const { return value; } }; template using BoolConstant = Constant; using True = BoolConstant; using False = BoolConstant; template constexpr T Constant::value; /* type equality */ template constexpr bool IsSame = false; template constexpr bool IsSame = true; /* is void */ template constexpr bool IsVoid = IsSame, void>; /* is null pointer */ template constexpr bool IsNullPointer = IsSame, Nullptr>; /* is integer */ namespace detail { template constexpr bool IsIntegralBase = false; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; template<> constexpr bool IsIntegralBase = true; } template constexpr bool IsIntegral = detail::IsIntegralBase>; /* is floating point */ namespace detail { template constexpr bool IsFloatingPointBase = false; template<> constexpr bool IsFloatingPointBase = true; template<> constexpr bool IsFloatingPointBase = true; template<> constexpr bool IsFloatingPointBase = true; } template constexpr bool IsFloatingPoint = detail::IsFloatingPointBase>; /* is array */ template constexpr bool IsArray = false; template constexpr bool IsArray = true; template constexpr bool IsArray = true; /* is pointer */ namespace detail { template constexpr bool IsPointerBase = false; template constexpr bool IsPointerBase = true; } template constexpr bool IsPointer = detail::IsPointerBase>; /* is lvalue reference */ template constexpr bool IsLvalueReference = false; template constexpr bool IsLvalueReference = true; /* is rvalue reference */ template constexpr bool IsRvalueReference = false; template constexpr bool IsRvalueReference = true; /* is reference */ template constexpr bool IsReference = IsLvalueReference || IsRvalueReference; /* is enum */ template constexpr bool IsEnum = __is_enum(T); /* is union */ template constexpr bool IsUnion = __is_union(T); /* is class */ template constexpr bool IsClass = __is_class(T); /* is function */ namespace detail { struct FunctionTestDummy {}; template char function_test(T *); template char function_test(FunctionTestDummy); template int function_test(...); template T &function_source(int); template FunctionTestDummy function_source(...); template || IsUnion || IsVoid || IsReference || IsNullPointer> constexpr bool IsFunctionBase = sizeof(function_test(function_source(0))) == 1; template constexpr bool IsFunctionBase = false; } /* namespace detail */ template constexpr bool IsFunction = detail::IsFunctionBase; /* is arithmetic */ template constexpr bool IsArithmetic = IsIntegral || IsFloatingPoint; /* is fundamental */ template constexpr bool IsFundamental = IsArithmetic || IsVoid || IsNullPointer; /* is compound */ template constexpr bool IsCompound = !IsFundamental; /* is pointer to member */ namespace detail { template constexpr bool IsMemberPointerBase = false; template constexpr bool IsMemberPointerBase = true; } template constexpr bool IsMemberPointer = detail::IsMemberPointerBase>; /* is pointer to member object */ namespace detail { template constexpr bool IsMemberObjectPointerBase = false; template constexpr bool IsMemberObjectPointerBase = !IsFunction; } template constexpr bool IsMemberObjectPointer = detail::IsMemberObjectPointerBase>; /* is pointer to member function */ namespace detail { template constexpr bool IsMemberFunctionPointerBase = false; template constexpr bool IsMemberFunctionPointerBase = IsFunction; } template constexpr bool IsMemberFunctionPointer = detail::IsMemberFunctionPointerBase>; /* is object */ template constexpr bool IsObject = !IsFunction && !IsVoid && !IsReference; /* is scalar */ template constexpr bool IsScalar = IsMemberPointer || IsPointer || IsEnum || IsNullPointer || IsArithmetic; /* is abstract */ template constexpr bool IsAbstract = __is_abstract(T); /* is const */ template constexpr bool IsConst = IsSame; /* is volatile */ template constexpr bool IsVolatile = IsSame; /* is empty */ template constexpr bool IsEmpty = __is_empty(T); /* is POD */ template constexpr bool IsPod = __is_pod(T); /* is polymorphic */ template constexpr bool IsPolymorphic = __is_polymorphic(T); /* is signed */ namespace detail { template constexpr bool IsSignedCore = T(-1) < T(0); template> constexpr bool IsSignedBase = false; template constexpr bool IsSignedBase = detail::IsSignedCore; } template constexpr bool IsSigned = detail::IsSignedBase; /* is unsigned */ namespace detail { template constexpr bool IsUnsignedCore = T(0) < T(-1); template> constexpr bool IsUnsignedBase = false; template constexpr bool IsUnsignedBase = detail::IsUnsignedCore; } template constexpr bool IsUnsigned = detail::IsUnsignedBase; /* is standard layout */ template constexpr bool IsStandardLayout = __is_standard_layout(T); /* is literal type */ template constexpr bool IsLiteralType = __is_literal_type(T); /* is trivially copyable */ template constexpr bool IsTriviallyCopyable = IsScalar>; /* is trivial */ template constexpr bool IsTrivial = __is_trivial(T); /* has virtual destructor */ template constexpr bool HasVirtualDestructor = __has_virtual_destructor(T); /* is constructible */ namespace detail { #define OSTD_MOVE(v) static_cast &&>(v) template struct Select2nd { using Type = T; }; struct Any { Any(...); }; template typename Select2nd< decltype(OSTD_MOVE(T(declval_in()...))), True >::Type is_ctible_test(T &&, A &&...); #undef OSTD_MOVE template False is_ctible_test(Any, A &&...); template constexpr bool CtibleCore = CommonTypeBase< decltype(is_ctible_test(declval_in(), declval_in()...)) >::Type::value; /* function types are not constructible */ template constexpr bool CtibleCore = false; /* scalars are default constructible, refs are not */ template constexpr bool CtibleCore = IsScalar; /* scalars and references are constructible from one arg if * implicitly convertible to scalar or reference */ template struct CtibleRef { static True test(T); static False test(...); }; template constexpr bool CtibleCore = CommonTypeBase< decltype(CtibleRef::test(declval_in())) >::Type::value; /* scalars and references are not constructible from multiple args */ template constexpr bool CtibleCore = false; /* treat scalars and refs separately */ template constexpr bool CtibleVoidCheck = CtibleCore< (IsScalar || IsReference), T, A... >; /* if any of T or A is void, IsConstructible should be false */ template constexpr bool CtibleVoidCheck = false; template constexpr bool CtibleContainsVoid = false; template<> constexpr bool CtibleContainsVoid<> = false; template constexpr bool CtibleContainsVoid = IsVoid || CtibleContainsVoid; /* entry point */ template constexpr bool Ctible = CtibleVoidCheck< CtibleContainsVoid || IsAbstract, T, A... >; /* array types are default constructible if their element type is */ template constexpr bool CtibleCore = Ctible>; /* otherwise array types are not constructible by this syntax */ template constexpr bool CtibleCore = false; /* incomplete array types are not constructible */ template constexpr bool CtibleCore = false; } /* namespace detail */ template constexpr bool IsConstructible = detail::Ctible; /* is default constructible */ template constexpr bool IsDefaultConstructible = IsConstructible; /* is copy constructible */ template constexpr bool IsCopyConstructible = IsConstructible> >; /* is move constructible */ template constexpr bool IsMoveConstructible = IsConstructible >; /* is assignable */ namespace detail { template typename detail::Select2nd< decltype((declval_in() = declval_in())), True >::Type assign_test(T &&, U &&); template False assign_test(Any, T &&); template || IsVoid> constexpr bool IsAssignableBase = CommonTypeBase< decltype(assign_test(declval_in(), declval_in())) >::Type::value; template constexpr bool IsAssignableBase = false; } /* namespace detail */ template constexpr bool IsAssignable = detail::IsAssignableBase; /* is copy assignable */ template constexpr bool IsCopyAssignable = IsAssignable< AddLvalueReference, AddLvalueReference> >; /* is move assignable */ template constexpr bool IsMoveAssignable = IsAssignable< AddLvalueReference, const AddRvalueReference >; /* is destructible */ namespace detail { template struct IsDtibleApply { using Type = int; }; template struct IsDestructorWellformed { template static char test(typename IsDtibleApply< decltype(detail::declval_in().~TT()) >::Type); template static int test(...); static constexpr bool value = (sizeof(test(12)) == sizeof(char)); }; template constexpr bool DtibleImpl = false; template constexpr bool DtibleImpl = IsDestructorWellformed>::value; template constexpr bool DtibleImpl = true; template constexpr bool DtibleFalse = false; template constexpr bool DtibleFalse = DtibleImpl>; template constexpr bool DtibleFalse = false; template constexpr bool IsDestructibleBase = detail::DtibleFalse>; template constexpr bool IsDestructibleBase = false; template< > constexpr bool IsDestructibleBase = false; } /* namespace detail */ template constexpr bool IsDestructible = detail::IsDestructibleBase; /* is trivially constructible */ namespace detail { template constexpr bool IsTriviallyConstructibleBase = false; template constexpr bool IsTriviallyConstructibleBase = __has_trivial_constructor(T); template constexpr bool IsTriviallyConstructibleBase = __has_trivial_copy(T); template constexpr bool IsTriviallyConstructibleBase = __has_trivial_copy(T); template constexpr bool IsTriviallyConstructibleBase = __has_trivial_copy(T); } /* namespace detail */ template constexpr bool IsTriviallyConstructible = detail::IsTriviallyConstructibleBase; /* is trivially default constructible */ template constexpr bool IsTriviallyDefaultConstructible = IsTriviallyConstructible; /* is trivially copy constructible */ template constexpr bool IsTriviallyCopyConstructible = IsTriviallyConstructible>; /* is trivially move constructible */ template constexpr bool IsTriviallyMoveConstructible = IsTriviallyConstructible>; /* is trivially assignable */ namespace detail { template constexpr bool IsTriviallyAssignableBase = false; template constexpr bool IsTriviallyAssignableBase = __has_trivial_assign(T); template constexpr bool IsTriviallyAssignableBase = __has_trivial_copy(T); template constexpr bool IsTriviallyAssignableBase = __has_trivial_copy(T); template constexpr bool IsTriviallyAssignableBase = __has_trivial_copy(T); } /* namespace detail */ template constexpr bool IsTriviallyAssignable = detail::IsTriviallyAssignableBase; /* is trivially copy assignable */ template constexpr bool IsTriviallyCopyAssignable = IsTriviallyAssignable>; /* is trivially move assignable */ template constexpr bool IsTriviallyMoveAssignable = IsTriviallyAssignable>; /* is trivially destructible */ template constexpr bool IsTriviallyDestructible = __has_trivial_destructor(T); /* is base of */ template constexpr bool IsBaseOf = __is_base_of(B, D); /* is convertible */ namespace detail { template || IsFunction || IsArray > struct IsConvertibleBase { static constexpr bool value = IsVoid; }; template struct IsConvertibleBase { template static void test_f(TT); template(declval_in())) > static True test(int); template static False test(...); static constexpr bool value = decltype(test(0))::value; }; } template constexpr bool IsConvertible = detail::IsConvertibleBase::value; /* extent */ namespace detail { template constexpr Size ExtentBase = 0; template constexpr Size ExtentBase = 0; template constexpr Size ExtentBase = detail::ExtentBase; template constexpr Size ExtentBase = N; template constexpr Size ExtentBase = detail::ExtentBase; } /* namespace detail */ template constexpr Size Extent = detail::ExtentBase; /* rank */ namespace detail { template constexpr Size RankBase = 0; template constexpr Size RankBase = detail::RankBase + 1; template constexpr Size RankBase = detail::RankBase + 1; } template constexpr Size Rank = detail::RankBase; /* remove const, volatile, cv */ namespace detail { template struct RemoveConstBase { using Type = T; }; template struct RemoveConstBase { using Type = T; }; template struct RemoveVolatileBase { using Type = T; }; template struct RemoveVolatileBase { using Type = T; }; } template using RemoveConst = typename detail::RemoveConstBase::Type; template using RemoveVolatile = typename detail::RemoveVolatileBase::Type; namespace detail { template struct RemoveCvBase { using Type = RemoveVolatile>; }; } /* add const, volatile, cv */ namespace detail { template || IsFunction || IsConst> struct AddConstCore { using Type = T; }; template struct AddConstCore { using Type = const T; }; template struct AddConstBase { using Type = typename AddConstCore::Type; }; template || IsFunction || IsVolatile> struct AddVolatileCore { using Type = T; }; template struct AddVolatileCore { using Type = volatile T; }; template struct AddVolatileBase { using Type = typename AddVolatileCore::Type; }; } template using AddVolatile = typename detail::AddVolatileBase::Type; namespace detail { template struct AddCvBase { using Type = AddConst>; }; } template using AddCv = typename detail::AddCvBase::Type; /* remove reference */ namespace detail { template struct RemoveReferenceBase { using Type = T; }; template struct RemoveReferenceBase { using Type = T; }; template struct RemoveReferenceBase { using Type = T; }; } /* remove pointer */ namespace detail { template struct RemovePointerBase { using Type = T; }; template struct RemovePointerBase { using Type = T; }; template struct RemovePointerBase { using Type = T; }; template struct RemovePointerBase { using Type = T; }; template struct RemovePointerBase { using Type = T; }; } template using RemovePointer = typename detail::RemovePointerBase::Type; /* add pointer */ namespace detail { template struct AddPointerBase { using Type = RemoveReference *; }; } template using AddPointer = typename detail::AddPointerBase::Type; /* add lvalue reference */ namespace detail { template struct AddLr { using Type = T &; }; template struct AddLr { using Type = T &; }; template<> struct AddLr { using Type = void; }; template<> struct AddLr { using Type = const void; }; template<> struct AddLr { using Type = volatile void; }; template<> struct AddLr { using Type = const volatile void; }; } /* add rvalue reference */ namespace detail { template struct AddRr { using Type = T &&; }; template<> struct AddRr { using Type = void; }; template<> struct AddRr { using Type = const void; }; template<> struct AddRr { using Type = volatile void; }; template<> struct AddRr { using Type = const volatile void; }; } /* remove extent */ namespace detail { template struct RemoveExtentBase { using Type = T; }; template struct RemoveExtentBase { using Type = T; }; template struct RemoveExtentBase { using Type = T; }; } template using RemoveExtent = typename detail::RemoveExtentBase::Type; /* remove all extents */ namespace detail { template struct RemoveAllExtentsBase { using Type = T; }; template struct RemoveAllExtentsBase { using Type = RemoveAllExtentsBase; }; template struct RemoveAllExtentsBase { using Type = RemoveAllExtentsBase; }; } /* make (un)signed * * this is bad, but i don't see any better way * shamelessly copied from graphitemaster @ neothyne */ namespace detail { template struct TypeList { using First = T; using Rest = U; }; /* not a type */ struct TlNat { TlNat() = delete; TlNat(const TlNat &) = delete; TlNat &operator=(const TlNat &) = delete; ~TlNat() = delete; }; using Stypes = TypeList>>>>; using Utypes = TypeList>>>>; template struct TypeFindFirst; template struct TypeFindFirst, N, true> { using Type = T; }; template struct TypeFindFirst, N, false> { using Type = typename TypeFindFirst::Type; }; template>, bool = IsVolatile> > struct ApplyCv { using Type = U; }; template struct ApplyCv { /* const */ using Type = const U; }; template struct ApplyCv { /* volatile */ using Type = volatile U; }; template struct ApplyCv { /* const volatile */ using Type = const volatile U; }; template struct ApplyCv { /* const */ using Type = const U &; }; template struct ApplyCv { /* volatile */ using Type = volatile U &; }; template struct ApplyCv { /* const volatile */ using Type = const volatile U &; }; template || IsEnum> struct MakeSignedCore {}; template || IsEnum> struct MakeUnsignedCore {}; template struct MakeSignedCore { using Type = typename TypeFindFirst::Type; }; template struct MakeUnsignedCore { using Type = typename TypeFindFirst::Type; }; template<> struct MakeSignedCore {}; template<> struct MakeSignedCore { using Type = short; }; template<> struct MakeSignedCore { using Type = int; }; template<> struct MakeSignedCore { using Type = long; }; template<> struct MakeSignedCore { using Type = sbyte; }; template<> struct MakeSignedCore { using Type = sbyte; }; template<> struct MakeSignedCore { using Type = short; }; template<> struct MakeSignedCore { using Type = int; }; template<> struct MakeSignedCore { using Type = long; }; template<> struct MakeSignedCore { using Type = llong; }; template<> struct MakeSignedCore { using Type = llong; }; template<> struct MakeUnsignedCore {}; template<> struct MakeUnsignedCore { using Type = ushort; }; template<> struct MakeUnsignedCore { using Type = uint; }; template<> struct MakeUnsignedCore { using Type = ulong; }; template<> struct MakeUnsignedCore { using Type = byte; }; template<> struct MakeUnsignedCore { using Type = byte; }; template<> struct MakeUnsignedCore { using Type = ushort; }; template<> struct MakeUnsignedCore { using Type = uint; }; template<> struct MakeUnsignedCore { using Type = ulong; }; template<> struct MakeUnsignedCore { using Type = ullong; }; template<> struct MakeUnsignedCore { using Type = ullong; }; template struct MakeSignedBase { using Type = typename ApplyCv>::Type >::Type; }; template struct MakeUnsignedBase { using Type = typename ApplyCv>::Type >::Type; }; } /* namespace detail */ template using MakeSigned = typename detail::MakeSignedBase::Type; template using MakeUnsigned = typename detail::MakeUnsignedBase::Type; /* conditional */ namespace detail { template struct ConditionalBase { using Type = T; }; template struct ConditionalBase { using Type = U; }; } template using Conditional = typename detail::ConditionalBase<_cond, T, U>::Type; /* result of call at compile time */ namespace detail { #define OSTD_FWD(T, _v) static_cast(_v) template inline auto rof_invoke(F &&f, A &&...args) -> decltype(OSTD_FWD(F, f)(OSTD_FWD(A, args)...)) { return OSTD_FWD(F, f)(OSTD_FWD(A, args)...); } template inline auto rof_invoke(T B::*pmd, D &&ref) -> decltype(OSTD_FWD(D, ref).*pmd) { return OSTD_FWD(D, ref).*pmd; } template inline auto rof_invoke(PMD &&pmd, P &&ptr) -> decltype((*OSTD_FWD(P, ptr)).*OSTD_FWD(PMD, pmd)) { return (*OSTD_FWD(P, ptr)).*OSTD_FWD(PMD, pmd); } template inline auto rof_invoke(T B::*pmf, D &&ref, A &&...args) -> decltype((OSTD_FWD(D, ref).*pmf)(OSTD_FWD(A, args)...)) { return (OSTD_FWD(D, ref).*pmf)(OSTD_FWD(A, args)...); } template inline auto rof_invoke(PMF &&pmf, P &&ptr, A &&...args) -> decltype(((*OSTD_FWD(P, ptr)).*OSTD_FWD(PMF, pmf)) (OSTD_FWD(A, args)...)) { return ((*OSTD_FWD(P, ptr)).*OSTD_FWD(PMF, pmf)) (OSTD_FWD(A, args)...); } #undef OSTD_FWD template struct ResultOfCore {}; template struct ResultOfCore(), detail::declval_in()...)))> { using type = decltype(rof_invoke(detail::declval_in(), detail::declval_in()...)); }; template struct ResultOfBase: ResultOfCore {}; } /* namespace detail */ template using ResultOf = typename detail::ResultOfBase::Type; /* enable if */ namespace detail { template struct EnableIfBase {}; template struct EnableIfBase { using Type = T; }; } template using EnableIf = typename detail::EnableIfBase::Type; /* decay */ namespace detail { template struct DecayBase { private: using U = RemoveReference; public: using Type = Conditional, RemoveExtent *, Conditional, AddPointer, RemoveCv> >; }; } template using Decay = typename detail::DecayBase::Type; /* common type */ namespace detail { template struct CommonTypeBase; template struct CommonTypeBase { using Type = Decay; }; template struct CommonTypeBase { using Type = Decay() : detail::declval_in())>; }; template struct CommonTypeBase { using Type = typename CommonTypeBase< typename CommonTypeBase::Type, V... >::Type; }; } template using CommonType = typename detail::CommonTypeBase::Type; /* aligned storage */ namespace detail { template struct AlignedTest { union Type { byte data[N]; MaxAlign align; }; }; template struct AlignedStorageBase { struct Type { alignas(A) byte data[N]; }; }; } template::Type) > using AlignedStorage = typename detail::AlignedStorageBase::Type; /* aligned union */ namespace detail { template constexpr Size AlignMax = 0; template constexpr Size AlignMax = N; template constexpr Size AlignMax = (N1 > N2) ? N1 : N2; template constexpr Size AlignMax = AlignMax, N...>; template struct AlignedUnionBase { static constexpr Size alignment_value = AlignMax; struct type { alignas(alignment_value) byte data[AlignMax]; }; }; } /* namespace detail */ template using AlignedUnion = typename detail::AlignedUnionBase::Type; /* underlying type */ namespace detail { /* gotta wrap, in a struct otherwise clang ICEs... */ template struct UnderlyingTypeBase { using Type = __underlying_type(T); }; } template using UnderlyingType = typename detail::UnderlyingTypeBase::Type; } /* namespace ostd */ #endif