/* Type traits for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OCTA_TRAITS_H #define OCTA_TRAITS_H #include #include "octa/types.h" namespace octa { /* forward declarations */ template struct __OctaRemoveCv; template struct __OctaAddLr; template struct __OctaAddRr; template struct __OctaAddConst; template struct IsReference; template struct __OctaRemoveReference; template struct __OctaRemoveAllExtents; template struct IsTriviallyDefaultConstructible; template struct __OctaCommonType; template using RemoveCv = typename __OctaRemoveCv::Type; template using AddLvalueReference = typename __OctaAddLr::Type; template using AddRvalueReference = typename __OctaAddRr::Type; template using AddConst = typename __OctaAddConst::Type; template using RemoveReference = typename __OctaRemoveReference::Type; template using RemoveAllExtents = typename __OctaRemoveAllExtents::Type; /* declval also defined here to avoid including utility.h */ template AddRvalueReference __octa_declval(); /* integral constant */ template struct IntegralConstant { static constexpr T value = val; typedef T ValType; typedef IntegralConstant Type; constexpr operator ValType() const { return value; } constexpr ValType operator()() const { return value; } }; typedef IntegralConstant True; typedef IntegralConstant False; template constexpr T IntegralConstant::value; /* is void */ template struct __OctaIsVoid : False {}; template< > struct __OctaIsVoid: True {}; template struct IsVoid: __OctaIsVoid> {}; /* is null pointer */ template struct __OctaIsNullPointer : False {}; template< > struct __OctaIsNullPointer: True {}; template struct IsNullPointer: __OctaIsNullPointer> {}; /* is integer */ template struct __OctaIsIntegral: False {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral: True {}; template<> struct __OctaIsIntegral< wchar_t>: True {}; template struct IsIntegral: __OctaIsIntegral> {}; /* is floating point */ template struct __OctaIsFloatingPoint: False {}; template<> struct __OctaIsFloatingPoint: True {}; template<> struct __OctaIsFloatingPoint: True {}; template<> struct __OctaIsFloatingPoint: True {}; template struct IsFloatingPoint: __OctaIsFloatingPoint> {}; /* is array */ template struct IsArray : False {}; template struct IsArray: True {}; template struct IsArray: True {}; /* is pointer */ template struct __OctaIsPointer : False {}; template struct __OctaIsPointer: True {}; template struct IsPointer: __OctaIsPointer> {}; /* 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 */ struct __OctaFunctionTestDummy {}; template char __octa_function_test(T *); template char __octa_function_test(__OctaFunctionTestDummy); template int __octa_function_test(...); template T &__octa_function_source(int); template __OctaFunctionTestDummy __octa_function_source(...); template::value || IsUnion::value || IsVoid::value || IsReference::value || IsNullPointer::value > struct __OctaIsFunction: IntegralConstant(__octa_function_source(0))) == 1 > {}; template struct __OctaIsFunction: False {}; template struct IsFunction: __OctaIsFunction {}; /* 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 */ template struct __OctaIsMemberPointer: False {}; template struct __OctaIsMemberPointer: True {}; template struct IsMemberPointer: __OctaIsMemberPointer> {}; /* is pointer to member object */ template struct __OctaIsMemberObjectPointer: False {}; template struct __OctaIsMemberObjectPointer: IntegralConstant::value > {}; template struct IsMemberObjectPointer: __OctaIsMemberObjectPointer> {}; /* is pointer to member function */ template struct __OctaIsMemberFunctionPointer: False {}; template struct __OctaIsMemberFunctionPointer: IntegralConstant::value > {}; template struct IsMemberFunctionPointer: __OctaIsMemberFunctionPointer> {}; /* 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 */ template struct IsSigned: IntegralConstant {}; /* is unsigned */ template struct IsUnsigned: IntegralConstant {}; /* 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 */ #define __OCTA_MOVE(v) static_cast &&>(v) template struct __OctaSelect2nd { typedef T Type; }; struct __OctaAny { __OctaAny(...); }; template typename __OctaSelect2nd< decltype(__OCTA_MOVE(T(__octa_declval()...))), True >::Type __octa_is_ctible_test(T &&, A &&...); #undef __OCTA_MOVE template False __octa_is_ctible_test(__OctaAny, A &&...); template struct __OctaCtibleCore: __OctaCommonType< decltype(__octa_is_ctible_test(__octa_declval(), __octa_declval()...)) >::Type {}; /* function types are not constructible */ template struct __OctaCtibleCore: False {}; /* scalars are default constructible, refs are not */ template struct __OctaCtibleCore: IsScalar {}; /* scalars and references are constructible from one arg if * implicitly convertible to scalar or reference */ template struct __OctaCtibleRef { static True test(T); static False test(...); }; template struct __OctaCtibleCore: __OctaCommonType< decltype(__OctaCtibleRef::test(__octa_declval())) >::Type {}; /* scalars and references are not constructible from multiple args */ template struct __OctaCtibleCore: False {}; /* treat scalars and refs separately */ template struct __OctaCtibleVoidCheck: __OctaCtibleCore< (IsScalar::value || IsReference::value), T, A... > {}; /* if any of T or A is void, IsConstructible should be false */ template struct __OctaCtibleVoidCheck: False {}; template struct __OctaCtibleContainsVoid; template<> struct __OctaCtibleContainsVoid<>: False {}; template struct __OctaCtibleContainsVoid { static constexpr bool value = IsVoid::value || __OctaCtibleContainsVoid::value; }; /* entry point */ template struct __OctaCtible: __OctaCtibleVoidCheck< __OctaCtibleContainsVoid::value || IsAbstract::value, T, A... > {}; /* array types are default constructible if their element type is */ template struct __OctaCtibleCore: __OctaCtible> {}; /* otherwise array types are not constructible by this syntax */ template struct __OctaCtibleCore: False {}; /* incomplete array types are not constructible */ template struct __OctaCtibleCore: False {}; template struct IsConstructible: __OctaCtible {}; /* is default constructible */ template struct IsDefaultConstructible: IsConstructible {}; /* is copy constructible */ template struct IsCopyConstructible: IsConstructible> > {}; /* is move constructible */ template struct IsMoveConstructible: IsConstructible > {}; /* is assignable */ template typename __OctaSelect2nd< decltype((__octa_declval() = __octa_declval())), True >::Type __octa_assign_test(T &&, U &&); template False __octa_assign_test(__OctaAny, T &&); template::value || IsVoid::value> struct __OctaIsAssignable: __OctaCommonType< decltype(__octa_assign_test(__octa_declval(), __octa_declval())) >::Type {}; template struct __OctaIsAssignable: False {}; template struct IsAssignable: __OctaIsAssignable {}; /* is copy assignable */ template struct IsCopyAssignable: IsAssignable< AddLvalueReference, AddLvalueReference> > {}; /* is move assignable */ template struct IsMoveAssignable: IsAssignable< AddLvalueReference, const AddRvalueReference > {}; /* is destructible */ template struct __OctaIsDtibleApply { typedef int Type; }; template struct IsDestructorWellformed { template static char test(typename __OctaIsDtibleApply< decltype(__octa_declval().~TT()) >::Type); template static int test(...); static constexpr bool value = (sizeof(test(12)) == sizeof(char)); }; template struct __OctaDtibleImpl; template struct __OctaDtibleImpl: IntegralConstant>::value > {}; template struct __OctaDtibleImpl: True {}; template struct __OctaDtibleFalse; template struct __OctaDtibleFalse : __OctaDtibleImpl::value> {}; template struct __OctaDtibleFalse: False {}; template struct IsDestructible: __OctaDtibleFalse::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 nothrow constructible */ template struct IsNothrowConstructible: False {}; template struct IsNothrowConstructible: IntegralConstant {}; template struct IsNothrowConstructible: IntegralConstant {}; template struct IsNothrowConstructible: IntegralConstant {}; template struct IsNothrowConstructible: IntegralConstant {}; /* is nothrow default constructible */ template struct IsNothrowDefaultConstructible: IsNothrowConstructible {}; /* is nothrow copy constructible */ template struct IsNothrowCopyConstructible: IsNothrowConstructible > {}; /* is nothrow move constructible */ template struct IsNothrowMoveConstructible: IsNothrowConstructible > {}; /* is nothrow assignable */ template struct IsNothrowAssignable: False {}; template struct IsNothrowAssignable: IntegralConstant {}; template struct IsNothrowAssignable: IntegralConstant {}; template struct IsNothrowAssignable: IntegralConstant {}; template struct IsNothrowAssignable: IntegralConstant {}; /* is nothrow copy assignable */ template struct IsNothrowCopyAssignable: IsNothrowAssignable > {}; /* is nothrow move assignable */ template struct IsNothrowMoveAssignable: IsNothrowAssignable > {}; /* is nothrow destructible */ template struct __OctaIsNothrowDtible; template struct __OctaIsNothrowDtible: False {}; template struct __OctaIsNothrowDtible: IntegralConstant::value || noexcept(__octa_declval().~T())) > {}; template struct IsNothrowDestructible: __OctaIsNothrowDtible::value > {}; template struct IsNothrowDestructible: IsNothrowDestructible {}; template struct IsNothrowDestructible: IsNothrowDestructible {}; template struct IsNothrowDestructible: IsNothrowDestructible {}; /* is base of */ template struct IsBaseOf: IntegralConstant {}; /* is convertible */ template::value || IsFunction::value || IsArray::value > struct __OctaIsConvertible { typedef typename IsVoid::Type Type; }; template struct __OctaIsConvertible { template static void test_f(TT); template(__octa_declval())) > static True test(int); template static False test(...); typedef decltype(test(0)) Type; }; template struct IsConvertible: __OctaIsConvertible::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 */ template struct __OctaRemoveConst { typedef T Type; }; template struct __OctaRemoveConst { typedef T Type; }; template struct __OctaRemoveVolatile { typedef T Type; }; template struct __OctaRemoveVolatile { typedef T Type; }; template using RemoveConst = typename __OctaRemoveConst::Type; template using RemoveVolatile = typename __OctaRemoveVolatile::Type; template struct __OctaRemoveCv { typedef RemoveVolatile> Type; }; /* add const, volatile, cv */ template::value || IsFunction::value || IsConst::value> struct __OctaAddConstBase { typedef T Type; }; template struct __OctaAddConstBase { typedef const T Type; }; template struct __OctaAddConst { typedef typename __OctaAddConstBase::Type Type; }; template::value || IsFunction::value || IsVolatile::value> struct __OctaAddVolatileBase { typedef T Type; }; template struct __OctaAddVolatileBase { typedef volatile T Type; }; template struct __OctaAddVolatile { typedef typename __OctaAddVolatileBase::Type Type; }; template using AddVolatile = typename __OctaAddVolatile::Type; template struct __OctaAddCv { typedef AddConst> Type; }; template using AddCv = typename __OctaAddCv::Type; /* remove reference */ template struct __OctaRemoveReference { typedef T Type; }; template struct __OctaRemoveReference { typedef T Type; }; template struct __OctaRemoveReference { typedef T Type; }; /* remove pointer */ template struct __OctaRemovePointer { typedef T Type; }; template struct __OctaRemovePointer { typedef T Type; }; template struct __OctaRemovePointer { typedef T Type; }; template struct __OctaRemovePointer { typedef T Type; }; template struct __OctaRemovePointer { typedef T Type; }; template using RemovePointer = typename __OctaRemovePointer::Type; /* add pointer */ template struct __OctaAddPointer { typedef RemoveReference *Type; }; template using AddPointer = typename __OctaAddPointer::Type; /* add lvalue reference */ template struct __OctaAddLr { typedef T &Type; }; template struct __OctaAddLr { typedef T &Type; }; template struct __OctaAddLr { typedef T &Type; }; template<> struct __OctaAddLr { typedef void Type; }; template<> struct __OctaAddLr { typedef const void Type; }; template<> struct __OctaAddLr { typedef volatile void Type; }; template<> struct __OctaAddLr { typedef const volatile void Type; }; /* add rvalue reference */ template struct __OctaAddRr { typedef T &&Type; }; template struct __OctaAddRr { typedef T &&Type; }; template struct __OctaAddRr { typedef T &&Type; }; template<> struct __OctaAddRr { typedef void Type; }; template<> struct __OctaAddRr { typedef const void Type; }; template<> struct __OctaAddRr { typedef volatile void Type; }; template<> struct __OctaAddRr { typedef const volatile void Type; }; /* remove extent */ template struct __OctaRemoveExtent { typedef T Type; }; template struct __OctaRemoveExtent { typedef T Type; }; template struct __OctaRemoveExtent { typedef T Type; }; template using RemoveExtent = typename __OctaRemoveExtent::Type; /* remove all extents */ template struct __OctaRemoveAllExtents { typedef T Type; }; template struct __OctaRemoveAllExtents { typedef RemoveAllExtents Type; }; template struct __OctaRemoveAllExtents { typedef RemoveAllExtents Type; }; /* make (un)signed * * this is bad, but i don't see any better way * shamelessly copied from graphitemaster @ neothyne */ template struct __OctaTl { typedef T first; typedef U rest; }; /* not a type */ struct __OctaNat { __OctaNat() = delete; __OctaNat(const __OctaNat &) = delete; __OctaNat &operator=(const __OctaNat &) = delete; ~__OctaNat() = delete; }; typedef __OctaTl>>>> stypes; typedef __OctaTl>>>> utypes; template struct __OctaTypeFindFirst; template struct __OctaTypeFindFirst<__OctaTl, N, true> { typedef T Type; }; template struct __OctaTypeFindFirst<__OctaTl, N, false> { typedef typename __OctaTypeFindFirst::Type Type; }; template>::value, bool = IsVolatile>::value > struct __OctaApplyCv { typedef U Type; }; template struct __OctaApplyCv { /* const */ typedef const U Type; }; template struct __OctaApplyCv { /* volatile */ typedef volatile U Type; }; template struct __OctaApplyCv { /* const volatile */ typedef const volatile U Type; }; template struct __OctaApplyCv { /* const */ typedef const U &Type; }; template struct __OctaApplyCv { /* volatile */ typedef volatile U &Type; }; template struct __OctaApplyCv { /* const volatile */ typedef const volatile U &Type; }; template::value || IsEnum::value> struct __OctaMakeSigned {}; template::value || IsEnum::value> struct __OctaMakeUnsigned {}; template struct __OctaMakeSigned { typedef typename __OctaTypeFindFirst::Type Type; }; template struct __OctaMakeUnsigned { typedef typename __OctaTypeFindFirst::Type Type; }; template<> struct __OctaMakeSigned {}; template<> struct __OctaMakeSigned { typedef schar Type; }; template<> struct __OctaMakeSigned { typedef schar Type; }; template<> struct __OctaMakeSigned { typedef short Type; }; template<> struct __OctaMakeSigned { typedef short Type; }; template<> struct __OctaMakeSigned { typedef int Type; }; template<> struct __OctaMakeSigned { typedef int Type; }; template<> struct __OctaMakeSigned { typedef long Type; }; template<> struct __OctaMakeSigned { typedef long Type; }; template<> struct __OctaMakeSigned { typedef llong Type; }; template<> struct __OctaMakeSigned { typedef llong Type; }; template<> struct __OctaMakeUnsigned {}; template<> struct __OctaMakeUnsigned { typedef uchar Type; }; template<> struct __OctaMakeUnsigned { typedef uchar Type; }; template<> struct __OctaMakeUnsigned { typedef ushort Type; }; template<> struct __OctaMakeUnsigned { typedef ushort Type; }; template<> struct __OctaMakeUnsigned { typedef uint Type; }; template<> struct __OctaMakeUnsigned { typedef uint Type; }; template<> struct __OctaMakeUnsigned { typedef ulong Type; }; template<> struct __OctaMakeUnsigned { typedef ulong Type; }; template<> struct __OctaMakeUnsigned { typedef ullong Type; }; template<> struct __OctaMakeUnsigned { typedef ullong Type; }; template struct __OctaMakeSignedBase { typedef typename __OctaApplyCv>::Type >::Type Type; }; template struct __OctaMakeUnsignedBase { typedef typename __OctaApplyCv>::Type >::Type Type; }; template using MakeSigned = typename __OctaMakeSignedBase::Type; template using MakeUnsigned = typename __OctaMakeUnsignedBase::Type; /* conditional */ template struct __OctaConditional { typedef T Type; }; template struct __OctaConditional { typedef U Type; }; template using Conditional = typename __OctaConditional::Type; /* result of call at compile time */ #define __OCTA_FWD(T, v) static_cast(v) template inline auto __octa_rof_invoke(F &&f, A &&...args) -> decltype(__OCTA_FWD(F, f)(__OCTA_FWD(A, args)...)) { return __OCTA_FWD(F, f)(__OCTA_FWD(A, args)...); } template inline auto __octa_rof_invoke(T B::*pmd, D &&ref) -> decltype(__OCTA_FWD(D, ref).*pmd) { return __OCTA_FWD(D, ref).*pmd; } template inline auto __octa_rof_invoke(PMD &&pmd, P &&ptr) -> decltype((*__OCTA_FWD(P, ptr)).*__OCTA_FWD(PMD, pmd)) { return (*__OCTA_FWD(P, ptr)).*__OCTA_FWD(PMD, pmd); } template inline auto __octa_rof_invoke(T B::*pmf, D &&ref, A &&...args) -> decltype((__OCTA_FWD(D, ref).*pmf)(__OCTA_FWD(A, args)...)) { return (__OCTA_FWD(D, ref).*pmf)(__OCTA_FWD(A, args)...); } template inline auto __octa_rof_invoke(PMF &&pmf, P &&ptr, A &&...args) -> decltype(((*__OCTA_FWD(P, ptr)).*__OCTA_FWD(PMF, pmf))(__OCTA_FWD(A, args)...)) { return ((*__OCTA_FWD(P, ptr)).*__OCTA_FWD(PMF, pmf))(__OCTA_FWD(A, args)...); } #undef __OCTA_FWD template struct __OctaResultOf {}; template struct __OctaResultOf(), __octa_declval()...)))> { using type = decltype(__octa_rof_invoke(__octa_declval(), __octa_declval()...)); }; template struct __OctaResultOfBase: __OctaResultOf {}; template using ResultOf = typename __OctaResultOfBase::Type; /* enable if */ template struct __OctaEnableIf {}; template struct __OctaEnableIf { typedef T Type; }; template using EnableIf = typename __OctaEnableIf::Type; /* decay */ template struct __OctaDecay { private: typedef RemoveReference U; public: typedef Conditional::value, RemoveExtent *, Conditional::value, AddPointer, RemoveCv> > Type; }; template using Decay = typename __OctaDecay::Type; /* common type */ template struct __OctaCommonType; template struct __OctaCommonType { typedef __OctaDecay Type; }; template struct __OctaCommonType { typedef __OctaDecay() : __octa_declval())> Type; }; template struct __OctaCommonType { typedef typename __OctaCommonType::Type, V...>::Type Type; }; template using CommonType = typename __OctaCommonType::Type; /* aligned storage */ template struct __OctaAlignedTest { union type { uchar data[N]; octa::max_align_t align; }; }; template struct __OctaAlignedStorage { struct type { alignas(A) uchar data[N]; }; }; template::Type) > using AlignedStorage = typename __OctaAlignedStorage::Type; /* aligned union */ template struct __OctaAlignMax; template struct __OctaAlignMax { static constexpr size_t value = N; }; template struct __OctaAlignMax { static constexpr size_t value = (N1 > N2) ? N1 : N2; }; template struct __OctaAlignMax { static constexpr size_t value = __OctaAlignMax<__OctaAlignMax::value, N...>::value; }; template struct __OctaAlignedUnion { static constexpr size_t alignment_value = __OctaAlignMax::value; struct type { alignas(alignment_value) uchar data[__OctaAlignMax::value]; }; }; template using AlignedUnion = typename __OctaAlignedUnion::Type; /* underlying type */ /* gotta wrap, in a struct otherwise clang ICEs... */ template struct __OctaUnderlyingType { typedef __underlying_type(T) Type; }; template using UnderlyingType = typename __OctaUnderlyingType::Type; } #endif