/* 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 struct IsReference; template struct IsTriviallyDefaultConstructible; 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 {}; /* is void */ namespace detail { template struct IsVoidBase : False {}; template< > struct IsVoidBase: True {}; } template struct IsVoid: detail::IsVoidBase> {}; /* is null pointer */ namespace detail { template struct IsNullPointerBase : False {}; template< > struct IsNullPointerBase: True {}; } template struct IsNullPointer: detail::IsNullPointerBase> {}; /* 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 struct IsIntegral: detail::IsIntegralBase> {}; /* is floating point */ namespace detail { template struct IsFloatingPointBase: False {}; template<> struct IsFloatingPointBase: True {}; template<> struct IsFloatingPointBase: True {}; template<> struct IsFloatingPointBase: True {}; } template struct IsFloatingPoint: detail::IsFloatingPointBase> {}; /* is array */ template struct IsArray : False {}; template struct IsArray: True {}; template struct IsArray: True {}; /* is pointer */ namespace detail { template struct IsPointerBase : False {}; template struct IsPointerBase: True {}; } template struct IsPointer: detail::IsPointerBase> {}; /* is lvalue reference */ template struct IsLvalueReference : False {}; template struct IsLvalueReference: True {}; /* is rvalue reference */ template struct IsRvalueReference : False {}; template struct IsRvalueReference: True {}; /* is enum */ template struct IsEnum: IntegralConstant {}; /* is union */ template struct IsUnion: IntegralConstant {}; /* is class */ template struct IsClass: IntegralConstant {}; /* 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::value || IsUnion::value || IsVoid::value || IsReference::value || IsNullPointer::value > struct IsFunctionBase: IntegralConstant(function_source(0))) == 1 > {}; template struct IsFunctionBase: False {}; } /* namespace detail */ template struct IsFunction: detail::IsFunctionBase {}; /* is arithmetic */ template struct IsArithmetic: IntegralConstant::value || IsFloatingPoint::value) > {}; /* is fundamental */ template struct IsFundamental: IntegralConstant::value || IsVoid::value || IsNullPointer::value) > {}; /* is compound */ template struct IsCompound: IntegralConstant::value > {}; /* is pointer to member */ namespace detail { template struct IsMemberPointerBase: False {}; template struct IsMemberPointerBase: True {}; } template struct IsMemberPointer: detail::IsMemberPointerBase> {}; /* is pointer to member object */ namespace detail { template struct IsMemberObjectPointerBase: False {}; template struct IsMemberObjectPointerBase: IntegralConstant::value > {}; } template struct IsMemberObjectPointer: detail::IsMemberObjectPointerBase> {}; /* is pointer to member function */ namespace detail { template struct IsMemberFunctionPointerBase: False {}; template struct IsMemberFunctionPointerBase: IntegralConstant::value > {}; } template struct IsMemberFunctionPointer: detail::IsMemberFunctionPointerBase> {}; /* is reference */ template struct IsReference: IntegralConstant::value || IsRvalueReference::value) > {}; /* is object */ template struct IsObject: IntegralConstant::value && !IsVoid::value && !IsReference::value) > {}; /* is scalar */ template struct IsScalar: IntegralConstant::value || IsPointer::value || IsEnum::value || IsNullPointer ::value || IsArithmetic::value) > {}; /* is abstract */ template struct IsAbstract: IntegralConstant {}; /* is const */ template struct IsConst : False {}; template struct IsConst: True {}; /* is volatile */ template struct IsVolatile : False {}; template struct IsVolatile: True {}; /* is empty */ template struct IsEmpty: IntegralConstant {}; /* is POD */ template struct IsPod: IntegralConstant {}; /* is polymorphic */ template struct IsPolymorphic: IntegralConstant {}; /* is signed */ namespace detail { template struct IsSignedBase: IntegralConstant {}; } template::value> struct IsSigned: False {}; template struct IsSigned: detail::IsSignedBase {}; /* is unsigned */ namespace detail { template struct IsUnsignedBase: IntegralConstant {}; } template::value> struct IsUnsigned: False {}; template struct IsUnsigned: detail::IsUnsignedBase {}; /* is standard layout */ template struct IsStandardLayout: IntegralConstant {}; /* is literal type */ template struct IsLiteralType: IntegralConstant {}; /* is trivially copyable */ template struct IsTriviallyCopyable: IntegralConstant>::value > {}; /* is trivial */ template struct IsTrivial: IntegralConstant {}; /* has virtual destructor */ template struct HasVirtualDestructor: IntegralConstant {}; /* 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: 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 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::value || IsReference::value), 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::value || CtibleContainsVoid::value; }; /* entry point */ template struct Ctible: CtibleVoidCheck< CtibleContainsVoid::value || IsAbstract::value, 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 struct IsConstructible: detail::Ctible {}; /* is default constructible */ template struct IsDefaultConstructible: IsConstructible {}; /* is copy constructible */ template struct IsCopyConstructible: IsConstructible> > {}; /* is move constructible */ template struct 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::value || IsVoid::value > struct IsAssignableBase: CommonTypeBase< decltype(assign_test(declval_in(), declval_in())) >::Type {}; template struct IsAssignableBase: False {}; } /* namespace detail */ template struct IsAssignable: detail::IsAssignableBase {}; /* is copy assignable */ template struct IsCopyAssignable: IsAssignable< AddLvalueReference, AddLvalueReference> > {}; /* is move assignable */ template struct 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::value> {}; template struct DtibleFalse: False {}; } /* namespace detail */ template struct IsDestructible: detail::DtibleFalse::value> {}; template struct IsDestructible: False {}; template< > struct IsDestructible: False {}; /* is trivially constructible */ template struct IsTriviallyConstructible: False {}; template struct IsTriviallyConstructible: IntegralConstant {}; template struct IsTriviallyConstructible: IntegralConstant {}; template struct IsTriviallyConstructible: IntegralConstant {}; template struct IsTriviallyConstructible: IntegralConstant {}; /* is trivially default constructible */ template struct IsTriviallyDefaultConstructible: IsTriviallyConstructible {}; /* is trivially copy constructible */ template struct IsTriviallyCopyConstructible: IsTriviallyConstructible > {}; /* is trivially move constructible */ template struct IsTriviallyMoveConstructible: IsTriviallyConstructible > {}; /* is trivially assignable */ template struct IsTriviallyAssignable: False {}; template struct IsTriviallyAssignable: IntegralConstant {}; template struct IsTriviallyAssignable: IntegralConstant {}; template struct IsTriviallyAssignable: IntegralConstant {}; template struct IsTriviallyAssignable: IntegralConstant {}; /* is trivially copy assignable */ template struct IsTriviallyCopyAssignable: IsTriviallyAssignable > {}; /* is trivially move assignable */ template struct IsTriviallyMoveAssignable: IsTriviallyAssignable > {}; /* is trivially destructible */ template struct IsTriviallyDestructible: IntegralConstant {}; /* is base of */ template struct IsBaseOf: IntegralConstant {}; /* is convertible */ namespace detail { template::value || IsFunction::value || IsArray::value > struct IsConvertibleBase { using Type = typename IsVoid::Type; }; 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 struct IsConvertible: detail::IsConvertibleBase::Type {}; /* type equality */ template struct IsSame : False {}; template struct IsSame: True {}; /* extent */ template struct Extent: IntegralConstant {}; template struct Extent: IntegralConstant {}; template struct Extent: IntegralConstant::value> {}; template struct Extent: IntegralConstant {}; template struct Extent: IntegralConstant::value> {}; /* rank */ template struct Rank: IntegralConstant {}; template struct Rank: IntegralConstant::value + 1> {}; template struct Rank: IntegralConstant::value + 1> {}; /* 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::value || IsFunction::value || IsConst::value> struct AddConstCore { using Type = T; }; template struct AddConstCore { using Type = const T; }; template struct AddConstBase { using Type = typename AddConstCore::Type; }; template::value || IsFunction::value || IsVolatile::value> 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>::value, bool = IsVolatile>::value > 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::value || IsEnum::value> struct MakeSignedCore {}; template::value || IsEnum::value> 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::value, RemoveExtent *, Conditional::value, 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