/* 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 IntegralConstant { static constexpr T value = val; using Value = T; using Type = IntegralConstant; constexpr operator Value() const { return value; } constexpr Value operator()() const { return value; } }; using True = IntegralConstant; using False = IntegralConstant; template constexpr T IntegralConstant::value; /* and */ namespace detail { template struct AndBase; template struct AndBase: False {}; template<> struct AndBase: True {}; template struct AndBase: IntegralConstant {}; template struct AndBase: AndBase {}; } template struct And: detail::AndBase {}; /* or */ namespace detail { template struct OrBase; template<> struct OrBase: False {}; template struct OrBase: OrBase {}; template struct OrBase: True {}; } template struct Or: detail::OrBase {}; /* not */ template struct Not: IntegralConstant {}; /* type equality */ namespace detail { template struct IsSameBase : False {}; template struct IsSameBase: True {}; } template constexpr bool IsSame = detail::IsSameBase::value; /* is void */ template constexpr bool IsVoid = IsSame, void>; /* is null pointer */ template constexpr bool IsNullPointer = IsSame, Nullptr>; /* is integer */ namespace detail { template struct IsIntegralBase: False {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; } template constexpr bool IsIntegral = detail::IsIntegralBase>::value; /* is floating point */ namespace detail { template struct IsFloatingPointBase: False {}; template<> struct IsFloatingPointBase: True {}; template<> struct IsFloatingPointBase: True {}; template<> struct IsFloatingPointBase: True {}; } template constexpr bool IsFloatingPoint = detail::IsFloatingPointBase>::value; /* is array */ namespace detail { template struct IsArrayBase : False {}; template struct IsArrayBase: True {}; template struct IsArrayBase: True {}; } template constexpr bool IsArray = detail::IsArrayBase::value; /* is pointer */ namespace detail { template struct IsPointerBase : False {}; template struct IsPointerBase: True {}; } template constexpr bool IsPointer = detail::IsPointerBase>::value; /* is lvalue reference */ namespace detail { template struct IsLvalueReferenceBase : False {}; template struct IsLvalueReferenceBase: True {}; } template constexpr bool IsLvalueReference = detail::IsLvalueReferenceBase::value; /* is rvalue reference */ namespace detail { template struct IsRvalueReferenceBase : False {}; template struct IsRvalueReferenceBase: True {}; } template constexpr bool IsRvalueReference = detail::IsRvalueReferenceBase::value; /* 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 > struct IsFunctionBase: IntegralConstant(function_source(0))) == 1 > {}; template struct IsFunctionBase: False {}; } /* namespace detail */ template constexpr bool IsFunction = detail::IsFunctionBase::value; /* 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 struct IsMemberPointerBase: False {}; template struct IsMemberPointerBase: True {}; } template constexpr bool IsMemberPointer = detail::IsMemberPointerBase>::value; /* is pointer to member object */ namespace detail { template struct IsMemberObjectPointerBase: False {}; template struct IsMemberObjectPointerBase: IntegralConstant > {}; } template constexpr bool IsMemberObjectPointer = detail::IsMemberObjectPointerBase>::value; /* is pointer to member function */ namespace detail { template struct IsMemberFunctionPointerBase: False {}; template struct IsMemberFunctionPointerBase: IntegralConstant > {}; } template constexpr bool IsMemberFunctionPointer = detail::IsMemberFunctionPointerBase>::value; /* 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 struct IsSignedCore: IntegralConstant {}; template> struct IsSignedBase: False {}; template struct IsSignedBase: detail::IsSignedCore {}; } template constexpr bool IsSigned = detail::IsSignedBase::value; /* is unsigned */ namespace detail { template struct IsUnsignedCore: IntegralConstant {}; template> struct IsUnsignedBase: False {}; template struct IsUnsignedBase: detail::IsUnsignedCore {}; } template constexpr bool IsUnsigned = detail::IsUnsignedBase::value; /* 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 struct CtibleCore: CommonTypeBase< decltype(is_ctible_test(declval_in(), declval_in()...)) >::Type {}; /* function types are not constructible */ template struct CtibleCore: False {}; /* scalars are default constructible, refs are not */ template struct CtibleCore: IntegralConstant> {}; /* 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 struct CtibleCore: CommonTypeBase< decltype(CtibleRef::test(declval_in())) >::Type {}; /* scalars and references are not constructible from multiple args */ template struct CtibleCore: False {}; /* treat scalars and refs separately */ template struct CtibleVoidCheck: CtibleCore< (IsScalar || IsReference), T, A... > {}; /* if any of T or A is void, IsConstructible should be false */ template struct CtibleVoidCheck: False {}; template struct CtibleContainsVoid; template<> struct CtibleContainsVoid<>: False {}; template struct CtibleContainsVoid { static constexpr bool value = IsVoid || CtibleContainsVoid::value; }; /* entry point */ template struct Ctible: CtibleVoidCheck< CtibleContainsVoid::value || IsAbstract, T, A... > {}; /* array types are default constructible if their element type is */ template struct CtibleCore: Ctible> {}; /* otherwise array types are not constructible by this syntax */ template struct CtibleCore: False {}; /* incomplete array types are not constructible */ template struct CtibleCore: False {}; } /* namespace detail */ template constexpr bool IsConstructible = detail::Ctible::value; /* 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> struct IsAssignableBase: CommonTypeBase< decltype(assign_test(declval_in(), declval_in())) >::Type {}; template struct IsAssignableBase: False {}; } /* namespace detail */ template constexpr bool IsAssignable = detail::IsAssignableBase::value; /* 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 struct DtibleImpl; template struct DtibleImpl: IntegralConstant>::value > {}; template struct DtibleImpl: True {}; template struct DtibleFalse; template struct DtibleFalse : DtibleImpl> {}; template struct DtibleFalse: False {}; template struct IsDestructibleBase: detail::DtibleFalse> {}; template struct IsDestructibleBase: False {}; template< > struct IsDestructibleBase: False {}; } /* namespace detail */ template constexpr bool IsDestructible = detail::IsDestructibleBase::value; /* is trivially constructible */ namespace detail { template struct IsTriviallyConstructibleBase: False {}; template struct IsTriviallyConstructibleBase: IntegralConstant {}; template struct IsTriviallyConstructibleBase: IntegralConstant {}; template struct IsTriviallyConstructibleBase: IntegralConstant {}; template struct IsTriviallyConstructibleBase: IntegralConstant {}; } /* namespace detail */ template constexpr bool IsTriviallyConstructible = detail::IsTriviallyConstructibleBase::value; /* 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 struct IsTriviallyAssignableBase: False {}; template struct IsTriviallyAssignableBase: IntegralConstant {}; template struct IsTriviallyAssignableBase: IntegralConstant {}; template struct IsTriviallyAssignableBase: IntegralConstant {}; template struct IsTriviallyAssignableBase: IntegralConstant {}; } /* namespace detail */ template constexpr bool IsTriviallyAssignable = detail::IsTriviallyAssignableBase::value; /* 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 { using Type = IntegralConstant>; }; template struct IsConvertibleBase { template static void test_f(TT); template(declval_in())) > static True test(int); template static False test(...); using Type = decltype(test(0)); }; } template constexpr bool IsConvertible = detail::IsConvertibleBase::Type::value; /* extent */ namespace detail { template struct ExtentBase: IntegralConstant {}; template struct ExtentBase: IntegralConstant {}; template struct ExtentBase: IntegralConstant::value> {}; template struct ExtentBase: IntegralConstant {}; template struct ExtentBase: IntegralConstant::value> {}; } /* namespace detail */ template constexpr Size Extent = detail::ExtentBase::value; /* rank */ namespace detail { template struct RankBase: IntegralConstant {}; template struct RankBase: IntegralConstant::value + 1> {}; template struct RankBase: IntegralConstant::value + 1> {}; } template constexpr Size Rank = detail::RankBase::value; /* 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 struct AlignMax; template struct AlignMax { static constexpr Size value = N; }; template struct AlignMax { static constexpr Size value = (N1 > N2) ? N1 : N2; }; template struct AlignMax { static constexpr Size value = AlignMax::value, N...>::value; }; template struct AlignedUnionBase { static constexpr Size alignment_value = AlignMax::value; struct type { alignas(alignment_value) byte data[AlignMax::value]; }; }; } /* 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