AuROXTL/Include/auROXTL/auTemplateMeta.hpp

501 lines
11 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: auTemplateMeta.hpp
Date: 2022-2-1
Author: Reece
***/
#pragma once
template <bool v>
struct AuBoolType
{
static constexpr bool value = v;
using value_type = bool;
using type = AuBoolType;
constexpr operator value_type() const noexcept
{
return value;
}
constexpr value_type operator()() const noexcept
{
return value;
}
};
using AuFalseType = AuBoolType<false>;
using AuTrueType = AuBoolType<true>;
#include "auTemplateMetaIsFunction.hpp"
template <class T>
using AuToValueType_t = typename T::value_type;
template <class T>
using AuToElementType_t = typename T::element_type;
template <class T>
using AuToIterator_t = typename T::iterator;
template <typename T>
static AuToIterator_t<T> AuToIterator(const T &a); // intended use case: `decltype(AuToIterator(myHashMap)) itr;`
template <typename T>
static AuToElementType_t<T> AuToElementType(const T &a);
template <typename T>
static AuToValueType_t<T> AuToValueType(const T &a);
template <class T, class U>
struct AuIsSame : AuFalseType
{};
template <class T>
struct AuIsSame<T, T> : AuTrueType
{};
template <class T, class U>
inline constexpr bool AuIsSame_v = AuIsSame<T, U>::value;
template <class>
inline constexpr bool AuIsConst_v = false;
template <class T>
inline constexpr bool AuIsConst_v<const T> = true;
namespace _audetail
{
template <class T>
AuBoolType<!__is_union(T)> IsClass(int T:: *);
template <class>
AuFalseType IsClass(...);
template <class B>
AuTrueType TestIsPtrConvertible(const volatile B *);
template <class>
AuFalseType TestIsPtrConvertible(const volatile void *);
template <class, typename>
auto TestIsBaseOf(...) -> AuTrueType;
template <class B, typename D>
auto TestIsBaseOf(int) -> decltype(TestIsPtrConvertible<B>(static_cast<D *>(nullptr)));
// yoinked: https://stackoverflow.com/a/40867906
template<typename Func, typename...Params> static auto IsCallable(int) -> decltype((void)AuDeclVal<Func>()(AuDeclVal<Params>()...), AuTrueType {});
template<typename Func, typename...Params> static AuFalseType IsCallable(...);
}
template <class T>
struct AuIsClass : decltype(_audetail::IsClass<T>(nullptr))
{};
template <class T>
inline constexpr bool AuIsClass_v = AuIsClass<T>::value;
template <class Base, typename Derived>
struct AuIsBaseOf :
AuBoolType<
AuIsClass_v<Base> &&
AuIsClass_v<Derived> &&
decltype(_audetail::TestIsBaseOf<Base, Derived>(0))::value
>
{};
template <class Base, typename Derived>
inline constexpr bool AuIsBaseOf_v = AuIsBaseOf<Base, Derived>::value;
template <class>
inline constexpr bool AuIsPointer_v = false;
template <class T>
inline constexpr bool AuIsPointer_v<T *> = true;
template <class T>
inline constexpr bool AuIsPointer_v<T *const> = true;
template <class T>
inline constexpr bool AuIsPointer_v<T *volatile> = true;
template <class T>
inline constexpr bool AuIsPointer_v<T *const volatile> = true;
template <class>
inline constexpr bool AuIsReference_v = false;
template <class T>
inline constexpr bool AuIsReference_v<T &> = true;
template <class T>
inline constexpr bool AuIsReference_v<T &&> = true;
template <class>
inline constexpr bool AuIsLValueReference_v = false;
template <class T>
inline constexpr bool AuIsLValueReference_v<T &> = true;
template <class>
inline constexpr bool AuIsRValueReference_v = false;
template <class T>
inline constexpr bool AuIsRValueReference_v<T &&> = true;
template <class T>
struct AuRemovePointer
{
typedef T type;
};
template <class T>
struct AuRemovePointer<T *>
{
typedef T type;
};
template <class T>
struct AuRemovePointer<T *const>
{
typedef T type;
};
template <class T>
struct AuRemovePointer<T *volatile>
{
typedef T type;
};
template <class T>
struct AuRemovePointer<T *const volatile>
{
typedef T type;
};
template <class T>
using AuRemovePointer_t = typename AuRemovePointer<T>::type;
template <class T>
using AuIsVoid = AuIsSame<void, T>;
template <class T>
inline constexpr bool AuIsVoid_v = AuIsVoid<T>::value;
template <class T>
struct AuRemoveReference
{
using type = T;
};
template <class T>
struct AuRemoveReference<T &>
{
using type = T;
};
template <class T>
struct AuRemoveReference<T &&>
{
using type = T;
};
template <class T>
using AuRemoveReference_t = typename AuRemoveReference<T>::type;
template <class T>
struct AuRemoveConst
{
typedef T type;
};
template <class T>
struct AuRemoveConst<const T>
{
typedef T type;
};
template <class T>
using AuRemoveConst_t = typename AuRemoveConst<T>::type;
template <class T>
struct AuRemoveVolatile
{
typedef T type;
};
template <class T>
struct AuRemoveVolatile<volatile T>
{
typedef T type;
};
template <class T>
using AuRemoveVolatile_t = typename AuRemoveVolatile<T>::type;
template <bool Test, class T = void>
struct AuEnableIf
{};
template <class T>
struct AuEnableIf<true, T>
{
using type = T;
};
template <class T>
struct AuAddPointer
{
using type = AuRemoveReference_t<T> *;
};
template <class T>
using AuAddPointer_t = typename AuAddPointer<T>::type;
template <class T>
struct AuAddLReference
{
using type = AuRemoveReference_t<T> &;
};
template <class T>
using AuAddLReference_t = typename AuAddLReference<T>::type;
template <class T>
struct AuAddRReference
{
using type = AuRemoveReference_t<T> &&;
};
template <class T>
using AuAddRReference_t = typename AuAddRReference<T>::type;
template <class T>
T &&AuDeclVal();
template <class T>
struct AuAddConst
{
using type = const T;
};
template <class T>
using AuAddConst_t = typename AuAddConst<T>::type;
template <class T>
using AuRemoveCV_t = AuRemoveConst_t<AuRemoveReference_t<T>>;
template <class T>
struct AuRemoveExtent
{
using type = T;
};
template <class T>
struct AuRemoveExtent<T[]>
{
using type = T;
};
template <class T, AuUInt Len>
struct AuRemoveExtent<T[Len]>
{
using type = T;
};
template <class T>
using AuRemoveExtent_t = typename AuRemoveExtent<T>::type;
template <class ... Ts>
using AuVoid_t = void;
template <class>
constexpr inline bool AuIsArray_v = false;
template <class T, size_t Len>
inline constexpr bool AuIsArray_v<T[Len]> = true;
template <class T>
inline constexpr bool AuIsArray_v<T[]> = true;
template <bool Test, class T = void>
using AuEnableIf_t = typename AuEnableIf<Test, T>::type;
template <class T, class ... Args>
struct AuIsConstructible
{
template <class C, class ... Args2> static constexpr AuTrueType Test(decltype(::new C(AuDeclVal<Args2>()...)));
template <class C, class ... Args2> static constexpr AuFalseType Test(...);
using type = decltype(Test<T, Args...>(0));
};
template <class T, class ... Args>
using AuIsConstructible_t = typename AuIsConstructible<T, Args ...>::type;
template <class T, class ... Args>
inline constexpr bool AuIsConstructible_v = AuIsConstructible<T, Args ...>::type::value;
template <bool Test, class T, class T2>
struct AuConditional
{
using type = T;
};
template <class T, class T2>
struct AuConditional<false, T, T2>
{
using type = T2;
};
template <bool Test, class T, class T2>
using AuConditional_t = typename AuConditional<Test, T, T2>::type;
template <class T>
using AuDecay_t = AuConditional_t<
AuIsArray_v<T>,
AuAddPointer_t<AuRemoveExtent_t<T>>,
AuConditional_t<
AuIsFunction_v<T>,
AuAddPointer_t<T>,
AuRemoveCV_t<T>
>
>;
template <class T>
struct AuDecay
{
using type = AuDecay_t<T>;
};
template <template <class...> class Base, typename Derived>
struct AuIsBaseOfTemplateImpl
{
template <class... Ts>
static constexpr AuTrueType Test(const Base<Ts...> *);
static constexpr AuFalseType Test(...);
using type = decltype(Test(AuDeclVal<AuRemoveReference_t<Derived> *>()));
};
template <template <class...> class Base, typename Derived>
using AuIsBaseOfTemplate = typename AuIsBaseOfTemplateImpl<Base, Derived>::type;
template <template <class...> class Base, typename Derived>
inline constexpr bool AuIsBaseOfTemplate_v = AuIsBaseOfTemplateImpl<Base, Derived>::type::value;
// :(
// we have a boost licensed call traits in auv8pp
#include <type_traits>
#if defined(AU_LANG_CPP_14)
template <class T, class... Args>
using AuResultOf_t = typename std::result_of_t<T, Args...>;
#else
template <class T, class... Args>
using AuResultOf_t = typename std::invoke_result_t<T, Args...>;
#endif
template <class Func, class ...Params>
struct AuCallable : decltype(_audetail::IsCallable<Func, Params...>(0))
{
};
template <class F, class... Args>
constexpr auto AuIsCallable_v = AuCallable<F, Args...>::value;
#include "auCopyMoveUtils.hpp"
template <AuUInt uSize, class T>
struct AU_ALIGN(uSize)
AuAlignTo : T
{
inline AuAlignTo() : T()
{
}
inline AuAlignTo(T &&t) : T(AuForward<T&&>(t))
{
}
inline AuAlignTo(const T &t) : T(t)
{
}
};
template <class Ret_t, class T, class ...Args>
static auto AuGetAmbiguousMethod2(Ret_t(T :: *a)(Args...))
{
return a;
}
// I dont think I can easily implement these in templates
// For the sake of syntax sugar, these will be macros for now
#define AuGetAmbiguousMethod(Ret_t, Args, T, Method) AuGetAmbiguousMethod2<Ret_t, T, AU_BRACKET_SCOPE Args >(&T::Method)
#define AuGetAmbiguousMethod_v AuGetAmbiguousMethod
namespace _audetail
{
// yoinking https://en.cppreference.com/w/cpp/types/common_type
template<class...>
struct common_type
{ };
template<class T>
struct common_type<T> : common_type<T, T>
{ };
namespace ctdetail
{
template<class...>
using void_t = void;
template<class T1, class T2>
using conditional_result_t = decltype(false ? AuDeclVal<T1>() : AuDeclVal<T2>());
template<class, class, class = void>
struct decay_conditional_result
{ };
template<class T1, class T2>
struct decay_conditional_result<T1, T2, void_t<conditional_result_t<T1, T2>>>
: AuDecay<conditional_result_t<T1, T2>>
{ };
template<class T1, class T2, class = void>
struct common_type_2_impl : decay_conditional_result<const T1 &, const T2 &>
{ };
template<class T1, class T2>
struct common_type_2_impl<T1, T2, void_t<conditional_result_t<T1, T2>>>
: decay_conditional_result<T1, T2>
{ };
}
template<class T1, class T2>
struct common_type<T1, T2>
: AuConditional<AuIsSame_v<T1, AuDecay_t<T1>> && AuIsSame_v<T2, AuDecay_t<T2>>,
ctdetail::common_type_2_impl<T1, T2>,
common_type<AuDecay_t<T1>, AuDecay_t<T2>>>::type
{};
namespace ctdetail
{
template<class AlwaysVoid, class T1, class T2, class...R>
struct common_type_multi_impl
{ };
template<class T1, class T2, class...R>
struct common_type_multi_impl<void_t<typename common_type<T1, T2>::type>, T1, T2, R...>
: common_type<typename common_type<T1, T2>::type, R...>
{ };
}
}
template <class T, class T2>
using AuCommonType = typename _audetail::common_type<T, T2>;
template <class T, class T2>
using AuCommonType_t = typename _audetail::common_type<T, T2>::type;