diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 35ed6e5..06e0c7a 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -103,7 +103,7 @@ }, "@@ewdk_cc_toolchain~//:ewdk_extension.bzl%toolchains": { "general": { - "bzlTransitiveDigest": "9JDci1UBSQRcNgV8CaGaG7lk1+ZmfO4FF//420jL10w=", + "bzlTransitiveDigest": "o8jWc/DKL6u/xdGVR7ZVOsdvrJWHczkHwS5vnpdr1b8=", "usagesDigest": "KWfyUyVJ/UQYtoURvUEdG5qx0XigX4CN/NfpTe9J3Ns=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, diff --git a/radiant/Algorithm.h b/radiant/Algorithm.h index 4b289bf..7f2ec40 100644 --- a/radiant/Algorithm.h +++ b/radiant/Algorithm.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/TypeTraits.h" #include "radiant/Utility.h" #include "radiant/TotallyRad.h" diff --git a/radiant/Atomic.h b/radiant/Atomic.h index 1985c2d..0b578fe 100644 --- a/radiant/Atomic.h +++ b/radiant/Atomic.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/detail/AtomicIntrinsics.h" namespace rad diff --git a/radiant/EmptyOptimizedPair.h b/radiant/EmptyOptimizedPair.h index 5f407d3..4d464af 100644 --- a/radiant/EmptyOptimizedPair.h +++ b/radiant/EmptyOptimizedPair.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/Utility.h" namespace rad diff --git a/radiant/Integer.h b/radiant/Integer.h index 97c22f1..4692e65 100644 --- a/radiant/Integer.h +++ b/radiant/Integer.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "radiant/TotallyRad.h" #include "radiant/TypeTraits.h" #include "radiant/Res.h" diff --git a/radiant/Iterator.h b/radiant/Iterator.h index 24b20c5..9f35987 100644 --- a/radiant/Iterator.h +++ b/radiant/Iterator.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/Utility.h" namespace rad diff --git a/radiant/Locks.h b/radiant/Locks.h index 7edadd3..ae1cdac 100644 --- a/radiant/Locks.h +++ b/radiant/Locks.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/TypeTraits.h" namespace rad diff --git a/radiant/Res.h b/radiant/Res.h index b4e03bf..d82b64a 100644 --- a/radiant/Res.h +++ b/radiant/Res.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/Result.h" namespace rad diff --git a/radiant/Result.h b/radiant/Result.h index 62ad158..b1acd9c 100644 --- a/radiant/Result.h +++ b/radiant/Result.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/TypeWrapper.h" #include diff --git a/radiant/ScopeExit.h b/radiant/ScopeExit.h index 2aad006..969b0ad 100644 --- a/radiant/ScopeExit.h +++ b/radiant/ScopeExit.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/Utility.h" namespace rad diff --git a/radiant/SharedPtr.h b/radiant/SharedPtr.h index 029dfb3..d869d2b 100644 --- a/radiant/SharedPtr.h +++ b/radiant/SharedPtr.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/Memory.h" #include "radiant/Atomic.h" #include "radiant/Locks.h" diff --git a/radiant/Span.h b/radiant/Span.h index 6e10c56..f4c5982 100644 --- a/radiant/Span.h +++ b/radiant/Span.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/Iterator.h" #include "radiant/Byte.h" diff --git a/radiant/TotallyRad.h b/radiant/TotallyRad.h index 8180005..3dc8b7b 100644 --- a/radiant/TotallyRad.h +++ b/radiant/TotallyRad.h @@ -152,26 +152,12 @@ static_assert(!(RAD_WINDOWS && RAD_MACOS), "env invalid os"); #error unsupported hardware #endif +#define RAD_UNUSED(x) ((void)x) + #include -#if RAD_WINDOWS -#if RAD_KERNEL_MODE +#if RAD_WINDOWS && RAD_KERNEL_MODE #include -#else -#define WIN32_LEAN_AND_MEAN -#define WIN32_NO_STATUS -#include -#undef WIN32_NO_STATUS -#include -#endif -#endif - -#if RAD_WINDOWS -#define RAD_UNUSED(x) UNREFERENCED_PARAMETER(x) -#define RAD_YIELD_PROCESSOR() YieldProcessor() -#else -#define RAD_UNUSED(x) ((void)x) -#define RAD_YIELD_PROCESSOR() sched_yield() #endif #define RAD_CONCAT_INNER(x, y) x##y diff --git a/radiant/TypeTraits.h b/radiant/TypeTraits.h index c49037f..4c0a42e 100644 --- a/radiant/TypeTraits.h +++ b/radiant/TypeTraits.h @@ -15,62 +15,61 @@ #pragma once #include "radiant/TotallyRad.h" - -#include +#include "radiant/detail/StdTypeTraits.h" namespace rad { template -using EnIf = typename std::enable_if::type; +using EnIf = typename enable_if::type; template -using Cond = typename std::conditional::type; +using Cond = typename conditional::type; template -using Decay = typename std::decay::type; +using Decay = typename decay::type; template -using RemoveRef = typename std::remove_reference::type; +using RemoveRef = typename remove_reference::type; template -using RemoveCV = typename std::remove_cv::type; +using RemoveCV = typename remove_cv::type; template -using RemoveConst = typename std::remove_const::type; +using RemoveConst = typename remove_const::type; template -RAD_INLINE_VAR constexpr bool IsSigned = std::is_signed::value; +RAD_INLINE_VAR constexpr bool IsSigned = is_signed::value; template RAD_INLINE_VAR constexpr bool IsUnsigned = !IsSigned; template -using MakeUnsigned = typename std::make_unsigned::type; +using MakeUnsigned = typename make_unsigned::type; template -RAD_INLINE_VAR constexpr bool IsConv = std::is_convertible::value; +RAD_INLINE_VAR constexpr bool IsConv = is_convertible::value; template -RAD_INLINE_VAR constexpr bool IsSame = std::is_same::value; +RAD_INLINE_VAR constexpr bool IsSame = is_same::value; template -RAD_INLINE_VAR constexpr bool IsConst = std::is_const::value; +RAD_INLINE_VAR constexpr bool IsConst = is_const::value; template -RAD_INLINE_VAR constexpr bool IsEmpty = std::is_empty::value; +RAD_INLINE_VAR constexpr bool IsEmpty = is_empty::value; template -RAD_INLINE_VAR constexpr bool IsRef = std::is_reference::value; +RAD_INLINE_VAR constexpr bool IsRef = is_reference::value; template -RAD_INLINE_VAR constexpr bool IsPtr = std::is_pointer::value; +RAD_INLINE_VAR constexpr bool IsPtr = is_pointer::value; template -RAD_INLINE_VAR constexpr bool IsLRef = std::is_lvalue_reference::value; +RAD_INLINE_VAR constexpr bool IsLRef = is_lvalue_reference::value; template -RAD_INLINE_VAR constexpr bool IsRRef = std::is_rvalue_reference::value; +RAD_INLINE_VAR constexpr bool IsRRef = is_rvalue_reference::value; namespace detail { @@ -93,7 +92,7 @@ struct IsLRefBindable public: static constexpr bool value = - sizeof(test(std::declval())) == sizeof(char); + sizeof(test(declval())) == sizeof(char); }; } // namespace detail @@ -102,132 +101,129 @@ template RAD_INLINE_VAR constexpr bool IsLRefBindable = detail::IsLRefBindable::value; -// std::decay not used here to avoid array-to-pointer/fn-to-pointer conversions +// decay not used here to avoid array-to-pointer/fn-to-pointer conversions // (based on a work-around by Luc Danton) template -RAD_INLINE_VAR constexpr bool IsRelated = IsSame< - typename std::remove_cv::type>::type, - typename std::remove_cv::type>::type>; +RAD_INLINE_VAR constexpr bool IsRelated = + IsSame::type>::type, + typename remove_cv::type>::type>; namespace detail { template -struct EnIfUnrelated : std::enable_if +struct EnIfUnrelated : enable_if { }; template -struct EnIfUnrelated : std::enable_if> +struct EnIfUnrelated : enable_if> { }; } // namespace detail template -using IntegralConstant = std::integral_constant; +using IntegralConstant = integral_constant; using TrueType = IntegralConstant; using FalseType = IntegralConstant; template -RAD_INLINE_VAR constexpr bool IsIntegral = std::is_integral::value; +RAD_INLINE_VAR constexpr bool IsIntegral = is_integral::value; template -RAD_INLINE_VAR constexpr bool IsPointer = std::is_pointer::value; +RAD_INLINE_VAR constexpr bool IsPointer = is_pointer::value; template using EnIfUnrelated = typename detail::EnIfUnrelated::type; template -RAD_INLINE_VAR constexpr bool IsCtor = - std::is_constructible::value; +RAD_INLINE_VAR constexpr bool IsCtor = is_constructible::value; template -RAD_INLINE_VAR constexpr bool IsTriv = std::is_trivial::value; +RAD_INLINE_VAR constexpr bool IsTriv = is_trivial::value; template RAD_INLINE_VAR constexpr bool IsTrivCtor = - std::is_trivially_constructible::value; + is_trivially_constructible::value; template RAD_INLINE_VAR constexpr bool IsNoThrowCtor = - std::is_nothrow_constructible::value; + is_nothrow_constructible::value; template RAD_INLINE_VAR constexpr bool IsDefaultCtor = - std::is_default_constructible::value; + is_default_constructible::value; template RAD_INLINE_VAR constexpr bool IsTrivDefaultCtor = - std::is_trivially_default_constructible::value; + is_trivially_default_constructible::value; template RAD_INLINE_VAR constexpr bool IsNoThrowDefaultCtor = - std::is_nothrow_default_constructible::value; + is_nothrow_default_constructible::value; template -RAD_INLINE_VAR constexpr bool IsCopyCtor = std::is_copy_constructible::value; +RAD_INLINE_VAR constexpr bool IsCopyCtor = is_copy_constructible::value; template RAD_INLINE_VAR constexpr bool IsTrivCopyCtor = - std::is_trivially_copy_constructible::value; + is_trivially_copy_constructible::value; template RAD_INLINE_VAR constexpr bool IsNoThrowCopyCtor = - std::is_nothrow_copy_constructible::value; + is_nothrow_copy_constructible::value; template -RAD_INLINE_VAR constexpr bool IsMoveCtor = std::is_move_constructible::value; +RAD_INLINE_VAR constexpr bool IsMoveCtor = is_move_constructible::value; template RAD_INLINE_VAR constexpr bool IsTrivMoveCtor = - std::is_trivially_move_constructible::value; + is_trivially_move_constructible::value; template RAD_INLINE_VAR constexpr bool IsNoThrowMoveCtor = - std::is_nothrow_move_constructible::value; + is_nothrow_move_constructible::value; template -RAD_INLINE_VAR constexpr bool IsAssign = std::is_assignable::value; +RAD_INLINE_VAR constexpr bool IsAssign = is_assignable::value; template RAD_INLINE_VAR constexpr bool IsTrivAssign = - std::is_trivially_assignable::value; + is_trivially_assignable::value; template RAD_INLINE_VAR constexpr bool IsNoThrowAssign = - std::is_nothrow_assignable::value; + is_nothrow_assignable::value; template -RAD_INLINE_VAR constexpr bool IsCopyAssign = std::is_copy_assignable::value; +RAD_INLINE_VAR constexpr bool IsCopyAssign = is_copy_assignable::value; template RAD_INLINE_VAR constexpr bool IsTrivCopyAssign = - std::is_trivially_copy_assignable::value; + is_trivially_copy_assignable::value; template RAD_INLINE_VAR constexpr bool IsNoThrowCopyAssign = - std::is_nothrow_copy_assignable::value; + is_nothrow_copy_assignable::value; template -RAD_INLINE_VAR constexpr bool IsMoveAssign = std::is_move_assignable::value; +RAD_INLINE_VAR constexpr bool IsMoveAssign = is_move_assignable::value; template RAD_INLINE_VAR constexpr bool IsTrivMoveAssign = - std::is_trivially_move_assignable::value; + is_trivially_move_assignable::value; template RAD_INLINE_VAR constexpr bool IsNoThrowMoveAssign = - std::is_nothrow_move_assignable::value; + is_nothrow_move_assignable::value; template -RAD_INLINE_VAR constexpr bool IsDtor = std::is_destructible::value; +RAD_INLINE_VAR constexpr bool IsDtor = is_destructible::value; template -RAD_INLINE_VAR constexpr bool IsTrivDtor = - std::is_trivially_destructible::value; +RAD_INLINE_VAR constexpr bool IsTrivDtor = is_trivially_destructible::value; template -RAD_INLINE_VAR constexpr bool IsNoThrowDtor = - std::is_nothrow_destructible::value; +RAD_INLINE_VAR constexpr bool IsNoThrowDtor = is_nothrow_destructible::value; namespace detail { @@ -236,16 +232,15 @@ RAD_INLINE_VAR constexpr bool AlwaysFalse = false; } template -typename std::add_rvalue_reference::type DeclVal() noexcept +typename add_rvalue_reference::type DeclVal() noexcept { RAD_S_ASSERTMSG(detail::AlwaysFalse, "Calling DeclVal is ill-formed"); } template -RAD_INLINE_VAR constexpr bool HasVirtualDtor = - std::has_virtual_destructor::value; +RAD_INLINE_VAR constexpr bool HasVirtualDtor = has_virtual_destructor::value; template -RAD_INLINE_VAR constexpr bool IsPoly = std::is_polymorphic::value; +RAD_INLINE_VAR constexpr bool IsPoly = is_polymorphic::value; } // namespace rad diff --git a/radiant/TypeWrapper.h b/radiant/TypeWrapper.h index 2b7dfdb..e5d6e02 100644 --- a/radiant/TypeWrapper.h +++ b/radiant/TypeWrapper.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/Utility.h" #if RAD_ENABLE_STD diff --git a/radiant/UniqueResource.h b/radiant/UniqueResource.h index 701d681..07eb32d 100644 --- a/radiant/UniqueResource.h +++ b/radiant/UniqueResource.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/Utility.h" namespace rad diff --git a/radiant/Utility.h b/radiant/Utility.h index 115598e..6b50344 100644 --- a/radiant/Utility.h +++ b/radiant/Utility.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/TypeTraits.h" namespace rad diff --git a/radiant/Vector.h b/radiant/Vector.h index 5a8201c..23cb3fd 100644 --- a/radiant/Vector.h +++ b/radiant/Vector.h @@ -14,6 +14,7 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/Memory.h" #include "radiant/EmptyOptimizedPair.h" #include "radiant/detail/VectorOperations.h" diff --git a/radiant/detail/AtomicIntrinsics.h b/radiant/detail/AtomicIntrinsics.h index bcfbb62..848f7ef 100644 --- a/radiant/detail/AtomicIntrinsics.h +++ b/radiant/detail/AtomicIntrinsics.h @@ -14,12 +14,27 @@ #pragma once +#include "radiant/TotallyRad.h" #include "radiant/Utility.h" #if RAD_WINDOWS && RAD_KERNEL_MODE #include #endif +#if RAD_WINDOWS && RAD_USER_MODE +#define WIN32_LEAN_AND_MEAN +#define WIN32_NO_STATUS +#include +#undef WIN32_NO_STATUS +#include +#endif + +#if RAD_WINDOWS +#define RAD_YIELD_PROCESSOR() YieldProcessor() +#else +#define RAD_YIELD_PROCESSOR() sched_yield() +#endif + namespace rad { enum class MemoryOrder : int diff --git a/radiant/detail/IntrinsicTraits.h b/radiant/detail/IntrinsicTraits.h new file mode 100644 index 0000000..58ce4dd --- /dev/null +++ b/radiant/detail/IntrinsicTraits.h @@ -0,0 +1,114 @@ +// Copyright 2024 The Radiant Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef RAD_MSC_VERSION +// MSVC does not seem to have something like __has_builtin, but +// also seems to define a superset of what the other compilers do +// in terms of intrinsics +#define __has_builtin(v) 1 +#endif + +#if __has_builtin(__is_enum) +#define INTRINSIC_IS_ENUM(T) __is_enum(T) +#else +RAD_S_ASSERTMSG(false, "compiler does not support intrinsic __is_enum") +#endif + +#if __has_builtin(__is_base_of) +#define INTRINSIC_IS_BASE_OF(B, D) __is_base_of(B, D) +#else +RAD_S_ASSERTMSG(false, "compiler does not support intrinsic __is_base_of") +#endif + +#if __has_builtin(__is_empty) +#define INTRINSIC_IS_EMPTY(T) __is_empty(T) +#else +RAD_S_ASSERTMSG(false, "compiler does not support intrinsic __is_empty") +#endif + +#if __has_builtin(__is_polymorphic) +#define INTRINSIC_IS_POLYMORPHIC(T) __is_polymorphic(T) +#else +RAD_S_ASSERTMSG(false, "compiler does not support intrinsic __is_polymorphic") +#endif + +#if __has_builtin(__is_trivially_destructible) +#define INTRINSIC_IS_TRIVIALLY_DESTRUCTIBLE(T) __is_trivially_destructible(T) +#elif __has_builtin(__has_trivial_destructor) +#define INTRINSIC_IS_TRIVIALLY_DESTRUCTIBLE(T) __has_trivial_destructor(T) +#else +RAD_S_ASSERTMSG(false, + "compiler does not support intrinsic for either " + "__is_trivially_destructible or __has_trivial_destructor"); +#endif + +#if __has_builtin(__is_assignable) +#define INTRINSIC_IS_ASSIGNABLE(L, R) __is_assignable(L, R) +#else +RAD_S_ASSERTMSG(false, "compiler does not support intrinsic __is_assignable"); +#endif + +#if __has_builtin(__is_constructible) +#define INTRINSIC_IS_CONSTRUCTIBLE(...) __is_constructible(__VA_ARGS__) +#else +RAD_S_ASSERTMSG(false, + "compiler does not support intrinsic __is_constructible"); +#endif + +#if __has_builtin(__is_trivially_assignable) +#define INTRINSIC_IS_TRIVIALLY_ASSIGNABLE(L, R) __is_trivially_assignable(L, R) +#else +RAD_S_ASSERTMSG( + false, "compiler does not support intrinsic __is_trivially_assignable"); +#endif + +#if __has_builtin(__is_trivially_constructible) +#define INTRINSIC_IS_TRIVIALLY_CONSTRUCTIBLE(...) \ + __is_trivially_constructible(__VA_ARGS__) +#else +RAD_S_ASSERTMSG( + false, "compiler does not support intrinsic __is_trivially_constructible"); +#endif + +#if __has_builtin(__is_nothrow_assignable) || defined(RAD_GCC_VERSION) +#define INTRINSIC_IS_NOTHROW_ASSIGNABLE(L, R) __is_nothrow_assignable(L, R) +#else +RAD_S_ASSERTMSG(false, + "compiler does not support intrinsic __is_nothrow_assignable"); +#endif + +#if __has_builtin(__is_nothrow_constructible) || defined(RAD_GCC_VERSION) +#define INTRINSIC_IS_NOTHROW_CONSTRUCTIBLE(...) \ + __is_nothrow_constructible(__VA_ARGS__) +#else +RAD_S_ASSERTMSG( + false, "compiler does not support intrinsic __is_nothrow_constructible"); +#endif + +#if __has_builtin(__is_trivial) +#define IS_TRIVIAL_IMPL(T) __is_trivial(T) +#else +#define IS_TRIVIAL_IMPL(T) \ + (is_trivially_copyable::value && \ + is_trivially_default_constructible::value) +#endif + +#if __has_builtin(__has_virtual_destructor) +#define INTRINSIC_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T) +#else +RAD_S_ASSERTMSG(false, + "compiler does not support intrinsic __has_virtual_destructor"); +#endif diff --git a/radiant/detail/Meta.h b/radiant/detail/Meta.h new file mode 100644 index 0000000..8b2f395 --- /dev/null +++ b/radiant/detail/Meta.h @@ -0,0 +1,219 @@ +// Copyright 2024 The Radiant Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +namespace rad +{ + +namespace meta +{ + +template +struct integral_constant +{ + static constexpr T value = val; + using value_type = T; + using type = integral_constant; + + constexpr operator value_type() const noexcept + { + return value; + } + + constexpr value_type operator()() const noexcept + { + return value; + } +}; + +using true_type = integral_constant; +using false_type = integral_constant; + +template +using VoidT = void; + +template +struct is_same : false_type +{ +}; + +template +struct is_same : true_type +{ +}; + +template +struct conditional +{ + using type = T; +}; + +template +struct conditional +{ + using type = F; +}; + +template +struct Identity +{ + using type = T; +}; + +template +struct Or; + +template <> +struct Or<> : public false_type +{ +}; + +template <> +struct Or : public true_type +{ +}; + +template <> +struct Or : public false_type +{ +}; + +template +struct Or + : public conditional>::type +{ +}; + +template +struct And; + +template <> +struct And<> : public true_type +{ +}; + +template <> +struct And : public true_type +{ +}; + +template <> +struct And : public false_type +{ +}; + +template +struct And + : public conditional, First>::type +{ +}; + +template +struct Not; + +template <> +struct Not : public false_type +{ +}; + +template <> +struct Not : public true_type +{ +}; + +template +struct TypeList +{ + static constexpr size_t size() noexcept + { + return sizeof...(Ts); + } +}; + +template +struct Front; + +template +struct Front> +{ + using Type = Head; +}; + +template +struct PopFront; + +template +struct PopFront> +{ + using Type = TypeList; +}; + +template +struct PushFront; + +template +struct PushFront, Item> +{ + using Type = TypeList; +}; + +template +struct GetAt; + +template +struct GetAt> +{ + using Type = typename GetAt>::Type; +}; + +template +struct GetAt<0, TypeList> +{ + using Type = Head; +}; + +template +struct GetAt> +{ + RAD_S_ASSERTMSG(N < TypeList<>::size(), "Index out of range"); +}; + +template +struct Contains; + +template +struct Contains> +{ + using Type = typename conditional< + is_same::value, + true_type, + typename Contains>::Type>::type; + static constexpr bool value = Type::value; +}; + +template +struct Contains> +{ + using Type = false_type; + static constexpr bool value = Type::value; +}; + +using Types = TypeList; +using FrontMissing = TypeList; + +} // namespace meta +} // namespace rad diff --git a/radiant/detail/StdTypeTraits.h b/radiant/detail/StdTypeTraits.h new file mode 100644 index 0000000..b5ce6d9 --- /dev/null +++ b/radiant/detail/StdTypeTraits.h @@ -0,0 +1,1356 @@ +// Copyright 2024 The Radiant Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#define USING_STL_TYPETRAITS 0 +#if USING_STL_TYPETRAITS + +#include + +namespace rad +{ + +using std::integral_constant; +using std::true_type; +using std::false_type; +using std::is_same; +using std::conditional; +using std::enable_if; +using std::remove_reference; +using std::remove_const; +using std::remove_volatile; +using std::remove_cv; +using std::remove_extent; +using std::remove_all_extents; +using std::add_rvalue_reference; +using std::add_pointer; +using std::add_cv; +using std::add_const; +using std::add_volatile; +using std::is_void; +using std::is_const; +using std::is_volatile; +using std::is_reference; +using std::is_lvalue_reference; +using std::is_rvalue_reference; +using std::is_pointer; +using std::is_null_pointer; +using std::is_member_pointer; +using std::is_array; +using std::is_enum; +using std::is_function; +using std::is_integral; +using std::is_floating_point; +using std::is_arithmetic; +using std::is_scalar; +using std::is_empty; +using std::is_polymorphic; +using std::is_assignable; +using std::is_constructible; +using std::is_copy_assignable; +using std::is_copy_constructible; +using std::is_default_constructible; +using std::is_destructible; +using std::is_move_assignable; +using std::is_move_constructible; +using std::is_trivially_assignable; +using std::is_trivially_constructible; +using std::is_trivially_copy_assignable; +using std::is_trivially_copy_constructible; +using std::is_trivially_default_constructible; +using std::is_trivially_destructible; +using std::is_trivially_move_assignable; +using std::is_trivially_move_constructible; +using std::is_nothrow_assignable; +using std::is_nothrow_constructible; +using std::is_nothrow_copy_assignable; +using std::is_nothrow_copy_constructible; +using std::is_nothrow_default_constructible; +using std::is_nothrow_destructible; +using std::is_nothrow_move_assignable; +using std::is_nothrow_move_constructible; +using std::is_trivial; +using std::is_signed; +using std::is_convertible; +using std::has_virtual_destructor; +using std::make_unsigned; +using std::decay; + +// NOTE: The declval function can only be used in unevaluated contexts. As +// alias definitions happen in evaluated context it is not possible to define +// an alias for declval. +/// typename add_rvalue_reference::type declval() noexcept; +/// @brief +/// @tparam T The type. +template +typename add_rvalue_reference::type declval() noexcept; + +namespace detail +{ +template +struct DeclvalSentinel +{ + static const bool evaluated = false; +}; +} // namespace detail + +template +typename add_rvalue_reference::type declval() noexcept +{ + RAD_S_ASSERTMSG(detail::DeclvalSentinel::evaluated, + "declval is not allowed in an evaluated context"); + return typename add_rvalue_reference::type(); +} +} // namespace rad + +#else + +#include "radiant/TotallyRad.h" +#include "radiant/detail/Meta.h" +#include "radiant/detail/IntrinsicTraits.h" + +namespace rad +{ + +/// template integral_constant; +/// @brief The base class for c++ type traits +/// @tparam T The type. +/// @tparam T The value which must be of type T. +template +using integral_constant = meta::integral_constant; + +/// true_type; +/// @brief The type representing the boolean value true +using true_type = meta::true_type; + +/// false_type; +/// @brief The type representing the boolean value false +using false_type = meta::false_type; + +/// template is_same; +/// @brief A meta function returning true if L and R are the same type +/// @tparam L The left hand type. +/// @tparam R The right hand type. +template +using is_same = meta::is_same; + +/// template conditional; +/// @brief Returns the type T if Cond is true otherwise returns the type F +/// @tparam Cond The condition. +/// @tparam T The type to return on true. +/// @tparam F They type to return on false. +template +using conditional = meta::conditional; + +/// template enable_if; +/// @brief Enables a template if bool is true +/// @tparam T a dummy type. +template +struct enable_if +{ +}; + +template +struct enable_if +{ + using type = T; +}; + +namespace detail +{ + +/// template is_referenceable; +/// @brief A meta function that returns true if a reference can be added to T +/// @tparam T The type. +template +struct is_referenceable : public false_type +{ +}; + +template +struct is_referenceable> : public true_type +{ +}; + +} // namespace detail + +/// template remove_reference; +/// @brief A meta function that removes a reference from T if one exists +/// @tparam T The type. +template +struct remove_reference +{ + using type = T; +}; + +template +struct remove_reference +{ + using type = T; +}; + +template +struct remove_reference +{ + using type = T; +}; + +/// template remove_const; +/// @brief A meta function that removes const from T if T is const +/// @tparam T The type. +template +struct remove_const +{ + using type = T; +}; + +template +struct remove_const +{ + using type = T; +}; + +/// template remove_volatile; +/// @brief A meta function that removes volatile from T if T is volatile +/// @tparam T The type. +template +struct remove_volatile +{ + using type = T; +}; + +/// +template +struct remove_volatile +{ + using type = T; +}; + +/// template remove_cv; +/// @brief a meta function that removes const and/or volatile if T is const +/// and/or volatile +/// @tparam T The type. +template +struct remove_cv +{ + using type = T; +}; + +template +struct remove_cv +{ + using type = T; +}; + +template +struct remove_cv +{ + using type = T; +}; + +template +struct remove_cv +{ + using type = T; +}; + +/// template remove_extent; +/// @brief A meta function that removes a single extent from an array +/// @tparam T The type. +template +struct remove_extent +{ + using type = T; +}; + +template +struct remove_extent +{ + using type = T; +}; + +template +struct remove_extent +{ + using type = T; +}; + +/// template remove_all_extents; +/// @brief A meta function that removes all extents from an array +/// @tparam T The type. +template +struct remove_all_extents +{ + using type = T; +}; + +template +struct remove_all_extents +{ + using type = typename remove_all_extents::type; +}; + +template +struct remove_all_extents +{ + using type = typename remove_all_extents::type; +}; + +/// template add_rvalue_reference; +/// @brief A meta function that adds an rvalue reference to T +/// @tparam T The type. +template ::value> +struct add_rvalue_reference +{ + using type = T; +}; + +template +struct add_rvalue_reference +{ + using type = T&&; +}; + +/// template add_pointer; +/// @brief A meta function that turns T into a pointer to T if T* is well formed +/// @tparam T The type. +namespace detail +{ +template +meta::Identity::type*> try_add_pointer(int); + +template +meta::Identity try_add_pointer(...); +} // namespace detail + +template +struct add_pointer : decltype(detail::try_add_pointer(0)) +{ +}; + +/// template add_cv; +/// @brief A meta function that adds const and/or volatile to T +/// @tparam T The type. +template +struct add_cv +{ + using type = const volatile T; +}; + +/// template add_const; +/// @brief A meta function that adds const to T +/// @tparam T The type. +template +struct add_const +{ + using type = const T; +}; + +/// template add_volatile; +/// @brief A meta function that adds volatile to T +/// @tparam T The type. +template +struct add_volatile +{ + using type = volatile T; +}; + +/// typename add_rvalue_reference::type declval() noexcept; +/// @brief A meta function that converts type T to a reference type +/// @tparam T The type. +template +typename add_rvalue_reference::type declval() noexcept; + +namespace detail +{ +template +struct DeclvalSentinel +{ + static const bool evaluated = false; +}; +} // namespace detail + +template +typename add_rvalue_reference::type declval() noexcept +{ + RAS_S_ASSERTMSG(detail::DeclvalSentinel::evaluated, + "declval is not allowed in an evaluated context"); + return typename add_rvalue_reference::type(); +} + +/// template is_void; +/// @brief A meta function that returns true if T is void +/// @tparam T The type. +template +struct is_void : public false_type +{ +}; + +template <> +struct is_void : public true_type +{ +}; + +template <> +struct is_void : public true_type +{ +}; + +template <> +struct is_void : public true_type +{ +}; + +template <> +struct is_void : public true_type +{ +}; + +/// template is_const; +/// @brief A meta function that returns true if T is const +/// @tparam T The type. +template +struct is_const : false_type +{ +}; + +template +struct is_const : true_type +{ +}; + +/// template is_volatile; +/// @brief A meta function that returns true if T is volatile +/// @tparam T The type. +template +struct is_volatile : false_type +{ +}; + +template +struct is_volatile : true_type +{ +}; + +/// template is_reference; +/// @brief A mete function that returns true if T is a reference type +/// @tparam T The type. +template +struct is_reference : false_type +{ +}; + +template +struct is_reference : true_type +{ +}; + +template +struct is_reference : true_type +{ +}; + +/// template is_lvalue_reference; +/// @brief A meta function that returns true if T is an lvalue reference +/// @tparam T The type. +template +struct is_lvalue_reference : false_type +{ +}; + +template +struct is_lvalue_reference : true_type +{ +}; + +/// template is_rvalue_reference; +/// @brief A meta function that returns true if T is an rvalue reference +/// @tparam T The type. +template +struct is_rvalue_reference : false_type +{ +}; + +template +struct is_rvalue_reference : true_type +{ +}; + +/// template is_pointer; +/// @brief A meta function that returns true if T is a pointer +/// @tparam T The type. +namespace detail +{ +template +struct is_pointer : public false_type +{ +}; + +template +struct is_pointer : public true_type +{ +}; +} // namespace detail + +template +struct is_pointer : public detail::is_pointer::type> +{ +}; + +/// template is_null_pointer; +/// @brief A meta function that returns true if T is nullptr +/// @tparam T The type. +namespace detail +{ +template +struct is_null_pointer : public false_type +{ +}; + +template <> +struct is_null_pointer : public true_type +{ +}; +} // namespace detail + +template +struct is_null_pointer + : public detail::is_null_pointer::type> +{ +}; + +/// template is_member_pointer; +/// @brief A meta function that returns true if T is a pointer to a class member +/// @tparam T The type. +namespace detail +{ +template +struct is_member_pointer : public false_type +{ +}; + +template +struct is_member_pointer : public true_type +{ +}; +} // namespace detail + +template +struct is_member_pointer + : public detail::is_member_pointer::type> +{ +}; + +/// template is_array; +/// @brief A meta function that returns true if T is an array +/// @tparam T The type. +template +struct is_array : false_type +{ +}; + +template +struct is_array : true_type +{ +}; + +template +struct is_array : true_type +{ +}; + +/// template is_enum; +/// @brief A meta function that returns true if T is an enum +/// @tparam T The type. +template +struct is_enum : public integral_constant +{ +}; + +/// template is_function; +/// @brief A meta function that returns true if T is a function +/// @tparam T The type. + +// So this is a clever trick someone invented and all compiler vendors +// implement is_function this way. Basically, you can const any type +// in C++ other than a function and a reference. So, if you have +// some type and you try to add const to it and and get back something +// that isn't const then T must be a function or a reference. So, if +// it is not a reference then it has to be a function. +// Unfortunately, MSVC likes to warn you if you try to const something +// that can't be const so we have to disable this warning here. +#ifdef RAD_MSC_VERSION +#pragma warning(push) +#pragma warning(disable : 4180) +#endif +template +struct is_function : integral_constant::value) && + (!is_reference::value)> +{ +}; +#ifdef RAD_MSC_VERSION +#pragma warning(pop) +#endif + +/// template is_integral; +/// @brief A meta function that returns true if T is an integral type +/// @tparam T The type +namespace detail +{ +#if RAD_CPP20 +using IntegralTypes = meta::TypeList; +#else +using IntegralTypes = meta::TypeList; +#endif +} // namespace detail + +template ::type> +using is_integral = typename meta::Contains; + +/// template is_floating_point; +/// @brief A meta function that returns true if T is a floating point type +/// @tparam T The type +namespace detail +{ +using FloatingPointTypes = meta::TypeList; + +#ifdef RAD_CPP23 +using FloatingPointTypes = meta::PushFront; +using FloatingPointTypes = meta::PushFront; +using FloatingPointTypes = meta::PushFront; +using FloatingPointTypes = meta::PushFront; +using FloatingPointTypes = meta::PushFront; +#endif +} // namespace detail + +template ::type> +using is_floating_point = + typename meta::Contains; + +/// template is_arithmetic; +/// @brief A meta function that returns true if T is an integral or floating +/// point type +/// @tparam T The type. +template +struct is_arithmetic : public integral_constant::value || + is_floating_point::value> +{ +}; + +/// template is_scalar; +/// @brief A meta function that returns true if T is a scalar type +/// @tparam T The type. +template +struct is_scalar : public meta::Or, + is_enum, + is_pointer, + is_member_pointer, + is_null_pointer>::type +{ +}; + +/// template is_empty; +/// @brief A meta function that returns true if T is a class type with no non- +/// static data members of size > 0 +/// @tparam T The type. +template +struct is_empty : public integral_constant +{ +}; + +/// template is_polymorphic; +/// @brief A meta function that returns true if T is a class that declares or +/// inherits at least one virtual function +/// @tparam T The type. +template +struct is_polymorphic + : public integral_constant +{ +}; + +/// template is_assignable; +/// @brief A meta function that returns true if T is assignable from U +/// @tparam T The type we are assigning to. +/// @tparam U The type we are assigning from. +template +struct is_assignable + : public integral_constant +{ +}; + +/// template is_constructible; +/// @brief A meta function that returns true if T has a constructor that can +/// be called with the parameter pack Args +/// @tparam T The type. +/// @tparam Args The Arguments to pass to the constructor +template +struct is_constructible + : public integral_constant +{ +}; + +/// template is_copy_assignable; +/// @brief A meta function that returns true if T has a copy assignment operator +/// @tparam T The type. +template ::value> +struct is_copy_assignable; + +template +struct is_copy_assignable : public false_type +{ +}; + +template +struct is_copy_assignable + : public integral_constant +{ +}; + +/// template is_copy_constructible; +/// @brief A meta function that returns true if T has a copy constructor +/// @tparam T The type. +template ::value> +struct is_copy_constructible; + +template +struct is_copy_constructible : public false_type +{ +}; + +template +struct is_copy_constructible + : public integral_constant +{ +}; + +/// template is_default_constructible; +/// @brief A meta function that returns true if T has a copy constructor +/// @tparam T The type. +template +struct is_default_constructible + : public integral_constant +{ +}; + +/// template is_destructible; +/// @brief A meta function that returns true if T is destructible +/// @tparam T The type. +template ::value || is_scalar::value, + bool IsFalse = is_void::value || is_function::value> +struct is_destructible; + +// true if T is a scalar or reference type. +template +struct is_destructible : public true_type +{ +}; + +// false if T is (possibly cv-qualified) void or a function type +template +struct is_destructible : public false_type +{ +}; + +// false if T is an array of unknown bound +template +struct is_destructible : public false_type +{ +}; + +namespace detail +{ +template +class destructor_well_formed +{ + template ().~U())> + static true_type CanDestruct(long); + + template + static false_type CanDestruct(...); + +public: + + using Type = decltype(CanDestruct(0)); +}; +} // namespace detail + +// true if with the extents removed the expression declval().~U() is +// well-formed in unevaluated context +template +struct is_destructible + : public detail::destructor_well_formed< + typename remove_all_extents::type>::Type +{ +}; + +// true if the expression declval().~U() is well-formed in unevaluated +// context +template +struct is_destructible + : public detail::destructor_well_formed::Type +{ +}; + +/// template is_move_assignable; +/// @brief A meta function that returns true if T has a move assignment operator +/// @tparam T The type. +template ::value> +struct is_move_assignable + : public integral_constant +{ +}; + +template +struct is_move_assignable : public false_type +{ +}; + +/// template is_move_constructible; +/// @brief A meta function that returns true if T has a move constructor +/// @tparam T The type. +template ::value> +struct is_move_constructible : public is_constructible +{ +}; + +template +struct is_move_constructible : public false_type +{ +}; + +/// template is_trivially_assignable; +/// @brief A meta function that returns true if T has a trivial assignment +/// operator from U +/// @tparam T The type we are assigning to. +/// @tparam U The type we are assigning from. +template +struct is_trivially_assignable + : public integral_constant +{ +}; + +/// template is_trivially_constructible; +/// @brief A meta function that returns true if T has a trivial constructor that +/// can take the parameter pack Args as its arguments +/// @tparam T The type. +/// @tparam Args The Arguments to pass to the constructor +template +struct is_trivially_constructible + : public integral_constant +{ +}; + +/// template is_trivially_copy_assignable; +/// @brief A meta function that returns true if T has a trivial copy assignment +/// operator +/// @tparam T The type. +template ::value> +struct is_trivially_copy_assignable + : public integral_constant +{ +}; + +template +struct is_trivially_copy_assignable : public false_type +{ +}; + +/// template is_trivially_copy_constructible; +/// @brief A meta function that returns true if T has a trivial copy constructor +/// @tparam T The type. +template ::value && + is_copy_constructible::value> +struct is_trivially_copy_constructible + : public integral_constant +{ +}; + +template +struct is_trivially_copy_constructible : public false_type +{ +}; + +/// template is_trivially_default_constructible; +/// @brief A meta function that returns true if T has a trivial default +/// constructor +/// @tparam T The type. +template +struct is_trivially_default_constructible + : public integral_constant +{ +}; + +/// template is_trivially_destructible; +/// @brief A meta function that returns true if T has a trivial destructor +/// @tparam T The type. +template ::value> +struct is_trivially_destructible + : public integral_constant +{ +}; + +template +struct is_trivially_destructible : public false_type +{ +}; + +/// template is_trivially_move_assignable; +/// @brief A meta function that returns true if T has a trivial move assignment +/// operator +/// @tparam T The type. +template ::value> +struct is_trivially_move_assignable + : public integral_constant +{ +}; + +template +struct is_trivially_move_assignable : public false_type +{ +}; + +/// template is_trivially_move_constructible; +/// @brief A meta function that returns true if T has a trivial move constructor +/// @tparam T The type. +template ::value && + is_move_constructible::value> +struct is_trivially_move_constructible + : public integral_constant +{ +}; + +template +struct is_trivially_move_constructible : public false_type +{ +}; + +/// template is_nothrow_assignable; +/// @brief A meta function that returns true if T has a noexcept assignment +/// operator that can take type U as input +/// @tparam T The type we are assigning to. +/// @tparam U The type we are assigning from. +template +struct is_nothrow_assignable + : public integral_constant +{ +}; + +/// template is_nothrow_constructible; +/// @brief A meta function that returns true if T has a noexcept constructor +/// that can take the expanded parameter pack Args as input +/// @tparam T The type. +/// @tparam Args The Arguments to pass to the constructor +template +struct is_nothrow_constructible + : public integral_constant +{ +}; + +/// template is_nothrow_copy_assignable; +/// @brief A meta function that returns true if T has a noexcept copy assignment +/// operator +/// @tparam T The type. +template ::value> +struct is_nothrow_copy_assignable : public is_nothrow_assignable +{ +}; + +template +struct is_nothrow_copy_assignable : public false_type +{ +}; + +/// template is_nothrow_copy_constructible; +/// @brief A meta function that returns true if T has a noexcept copy +/// constructor +/// @tparam T The type. +template ::value> +struct is_nothrow_copy_constructible + : public is_nothrow_constructible +{ +}; + +template +struct is_nothrow_copy_constructible : public false_type +{ +}; + +/// template is_nothrow_default_constructible; +/// @brief A meta function that returns true if T has a noexcept default +/// constructor +/// @tparam T The type. +template +struct is_nothrow_default_constructible + : public integral_constant +{ +}; + +/// template is_nothrow_destructible; +/// @brief A meta function that returns true if T has a noexcept destructor +/// @tparam T The type. +template ::value || is_scalar::value, + bool IsFalse = is_void::value || is_function::value> +struct is_nothrow_destructible; + +namespace detail +{ +template +class noexcept_destructor_well_formed +{ + template + static integral_constant().~U())> CanDestruct( + long); + + template + static false_type CanDestruct(...); + +public: + + using Type = decltype(CanDestruct(0)); +}; +} // namespace detail + +// true if T is a scalar or reference type. +template +struct is_nothrow_destructible : public true_type +{ +}; + +// false if T is (possibly cv-qualified) void or a function type +template +struct is_nothrow_destructible : public false_type +{ +}; + +// false if T is an array of unknown bound +template +struct is_nothrow_destructible : public false_type +{ +}; + +// true if with the extents removed the expression declval().~U() is +// well-formed in unevaluated context +template +struct is_nothrow_destructible + : public detail::noexcept_destructor_well_formed< + typename remove_all_extents::type>::Type +{ +}; + +// true if the expression declval().~U() is well-formed in unevaluated +// context +template +struct is_nothrow_destructible + : public detail::noexcept_destructor_well_formed::Type +{ +}; + +/// template is_nothrow_move_assignable; +/// @brief A meta function that returns true if T has a noexcept move assignment +/// operator +/// @tparam T The type. +template ::value> +struct is_nothrow_move_assignable : public is_nothrow_assignable +{ +}; + +template +struct is_nothrow_move_assignable : public false_type +{ +}; + +/// template is_nothrow_move_constructible; +/// @brief A meta function that returns true if T has a noexcept move +/// constructor +/// @tparam T The type. +template ::value> +struct is_nothrow_move_constructible : public is_nothrow_constructible +{ +}; + +template +struct is_nothrow_move_constructible : public false_type +{ +}; + +/// template is_trivial; +/// @brief A meta function that returns true if T is a trivial type +/// @tparam T The type. +template +struct is_trivial : public integral_constant +{ +}; + +/// template is_signed; +/// @brief A meta function that returns true if T is a signed type +/// @tparam T The type. +template ::value> +struct is_signed : integral_constant +{ +}; + +template +struct is_signed : false_type +{ +}; + +/// template is_convertible; +/// @brief A meta function that returns true if From can be implicitly converted +/// to To +/// @tparam From The input type +/// @tparam To The output type +template +class is_convertible +{ + + using NoCheckConversion = + typename meta::Or::type, + typename is_function::type, + typename is_array::type>::type; + + using IsVoid = + typename meta::And::type, NoCheckConversion>::type; + + template + static void TestDecl(Out) noexcept; + + // This template is selected if a call to a function taking a type Out and + // accepting as input the return of a function returning a reference to type + // In is well-formed. This will only be well-formed if an implicit + // conversion from type In to type Out exists. + template (declval()))> + static true_type Convert(long); + + template + static false_type Convert(...); + +public: + + // Here we first prune out some stuff we do not want to run through the + // implicit conversion test (the only thing that converts in this case is + // void to void), then we check for an implicit conversion. + using type = typename conditional(0))>::type; + static constexpr bool value = type::value; +}; + +/// template has_virtual_destructor; +/// @brief Does the type have a virtual destructor +/// @tparam T The type. +template +struct has_virtual_destructor + : public integral_constant +{ +}; + +/// template make_unsigned; +/// @brief Converts type T to the unsigned version of it if such a type exists +/// @tparam T The type. +template +struct make_unsigned; + +namespace detail +{ + +template +struct unsign; + +// Prevent bool conversions +template <> +struct unsign; + +template <> +struct unsign +{ + using type = unsigned char; +}; + +template <> +struct unsign +{ + using type = unsigned char; +}; + +template <> +struct unsign +{ + using type = unsigned char; +}; + +template <> +struct unsign +{ + using type = unsigned short; +}; + +template <> +struct unsign +{ + using type = unsigned short; +}; + +template <> +struct unsign +{ + using type = unsigned int; +}; + +template <> +struct unsign +{ + using type = unsigned int; +}; + +template <> +struct unsign +{ + using type = unsigned long; +}; + +template <> +struct unsign +{ + using type = unsigned long; +}; + +template <> +struct unsign +{ + using type = unsigned long long; +}; + +template <> +struct unsign +{ + using type = unsigned long long; +}; + +template +using ConvertToUnsigned = typename conditional< + sizeof(T) == 8, + uint64_t, + typename conditional< + sizeof(T) == 4, + uint32_t, + typename conditional< + sizeof(T) == 2, + uint16_t, + typename conditional::type>::type>:: + type>::type; + +#if RAD_CPP20 +using NonSignableChar = meta::TypeList; +#else +using NonSignableChar = meta::TypeList; +#endif + +template +using IsNonSignableChar = typename meta::Contains; + +template ::type, + bool IsConst = is_const::value, + bool IsVolatile = is_volatile::value, + bool NeedsConversion = + IsNonSignableChar::value || is_enum::value> +class cv_holder +{ + using converted_type = typename conditional, + WithoutCV>::type; + using unsigned_type = typename unsign::type; + using with_volatile = + typename conditional::type, + unsigned_type>::type; + +public: + + using type = typename conditional::type, + with_volatile>::type; +}; +} // namespace detail + +template +struct make_unsigned : detail::cv_holder +{ +}; + +/// template decay; +/// @brief Returns the type you would get if you passed T to a function by +/// value (i.e. arrays become pointers, functions become function +/// pointers...). +/// @tparam T The type. +template +struct decay +{ + using TNoRef = typename remove_reference::type; + using type = typename conditional< + is_array::value, + typename add_pointer::type>::type, + typename conditional::value, + typename add_pointer::type, + typename remove_cv::type>::type>::type; +}; +} // namespace rad + +#endif diff --git a/test/test_StdTypeTraits.cpp b/test/test_StdTypeTraits.cpp new file mode 100644 index 0000000..565317e --- /dev/null +++ b/test/test_StdTypeTraits.cpp @@ -0,0 +1,1201 @@ +// Copyright 2023 The Radiant Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" + +#include "radiant/detail/StdTypeTraits.h" +#include "radiant/detail/Meta.h" + +namespace rad +{ + +// Clang warns about this, but these are test data structures they are supposed +// to have unused private fields. +#ifdef RAD_CLANG_VERSION +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +enum class Enum8 : uint8_t +{ +}; +enum class Enum16 : uint16_t +{ +}; +enum class Enum32 : uint32_t +{ +}; +enum class Enum64 : uint64_t +{ +}; + +enum OldEnum +{ +}; + +union Union +{ + int val1; + long val2; +}; + +union EmptyUnion +{ +}; + +class ClassWithEmptyUnion +{ + EmptyUnion e; +}; + +class Trivial +{ + int val; +}; + +struct NonTrivial +{ + NonTrivial() + { + } + + NonTrivial(int) + { + } + + NonTrivial(const NonTrivial&) + { + } + + NonTrivial(NonTrivial&&) + { + } + + NonTrivial& operator=(const NonTrivial&) + { + return *this; + } + + NonTrivial& operator=(const NonTrivial&&) + { + return *this; + } + + ~NonTrivial() + { + } +}; + +class Base +{ +}; + +class Derived : public Base +{ +}; + +class VirtualBase +{ + virtual ~VirtualBase() + { + } +}; + +class PureVirtualBase +{ + virtual int foo() = 0; +}; + +class VirtualDerivedEmpty : virtual Base +{ +}; + +class DerivedPureVirtual : public PureVirtualBase +{ + int foo() override + { + return 1; + } +}; + +class Convertable +{ +}; + +class Convert +{ +public: + + operator Convertable() const + { + return c; + } + + Convertable c; +}; + +class AlwaysConvertable +{ +public: + + template + AlwaysConvertable(T&&) + { + } +}; + +int PlainFunction(); + +struct MemberFunctionTester +{ + void operator()() + { + } + + static int Static(); + int Member() const&; +}; + +struct NoThrow +{ + NoThrow() noexcept + { + } + + NoThrow(int) noexcept + { + } + + NoThrow(const NoThrow&) noexcept + { + } + + NoThrow(NoThrow&&) noexcept + { + } + + NoThrow& operator=(const NoThrow&) noexcept + { + return *this; + } + + NoThrow& operator=(const NoThrow&&) noexcept + { + return *this; + } + + ~NoThrow() noexcept + { + } +}; + +struct Throw +{ + Throw() + { + } + + Throw(int) + { + } + + Throw(const Throw&) + { + } + + Throw(Throw&&) + { + } + + Throw& operator=(const Throw&) + { + return *this; + } + + Throw& operator=(const Throw&&) + { + return *this; + } + + ~Throw() + { + } +}; + +struct NoOps +{ + NoOps() noexcept = delete; + NoOps(int) noexcept = delete; + NoOps(const NoOps&) noexcept = delete; + NoOps(NoOps&&) noexcept = delete; + + NoOps& operator=(const NoOps&) noexcept = delete; + NoOps& operator=(const NoOps&&) noexcept = delete; + +private: + + ~NoOps() noexcept = default; +}; + +#ifdef RAD_CLANG_VERSION +#pragma clang diagnostic pop +#endif + +RAD_S_ASSERT(meta::Or<>::value == false); +RAD_S_ASSERT(meta::Or::value == false); +RAD_S_ASSERT(meta::Or::value == true); +RAD_S_ASSERT((meta::Or::value == true)); +RAD_S_ASSERT((meta::Or::value == true)); +RAD_S_ASSERT((meta::Or::value == true)); +RAD_S_ASSERT((meta::Or::value == false)); +RAD_S_ASSERT((meta::Or::value == false)); +RAD_S_ASSERT((meta::Or::value == true)); +RAD_S_ASSERT((meta::Or::value == + true)); + +RAD_S_ASSERT(meta::And<>::value == true); +RAD_S_ASSERT(meta::And::value == false); +RAD_S_ASSERT(meta::And::value == true); +RAD_S_ASSERT((meta::And::value == true)); +RAD_S_ASSERT((meta::And::value == false)); +RAD_S_ASSERT((meta::And::value == false)); +RAD_S_ASSERT((meta::And::value == false)); +RAD_S_ASSERT((meta::And::value == true)); +RAD_S_ASSERT((meta::And::value == false)); +RAD_S_ASSERT((meta::And::value == + false)); + +/// template is_same; +#define CheckIsSame(L, R) \ + RAD_S_ASSERT((is_same::value == std::is_same::value)) + +CheckIsSame(int, int); +CheckIsSame(int, long); +CheckIsSame(Base, Base); +CheckIsSame(Base, Derived); +CheckIsSame(Derived, Base); +CheckIsSame(Base, Derived); + +/// template conditional; +#define CheckConditional(Cond, T, F) \ + RAD_S_ASSERT((is_same::type, \ + std::conditional::type>::value)) + +CheckConditional(true, true_type, false_type); +CheckConditional(false, true_type, false_type); + +/// template remove_reference; +#define CheckRemoveReference(T) \ + RAD_S_ASSERT((is_same::type, \ + std::remove_reference::type>::value)) + +CheckRemoveReference(int); +CheckRemoveReference(int&); +CheckRemoveReference(int&&); +CheckRemoveReference(const int&); +CheckRemoveReference(volatile int&); +CheckRemoveReference(const volatile int&); + +/// template remove_const; +#define CheckRemoveConst(T) \ + RAD_S_ASSERT( \ + (is_same::type, std::remove_const::type>::value)) + +CheckRemoveConst(int); +CheckRemoveConst(const int); +CheckRemoveConst(volatile int); +CheckRemoveConst(const volatile int); + +/// template remove_volatile; +#define CheckRemoveVolatile(T) \ + RAD_S_ASSERT((is_same::type, \ + std::remove_volatile::type>::value)) + +CheckRemoveVolatile(int); +CheckRemoveVolatile(const int); +CheckRemoveVolatile(volatile int); +CheckRemoveVolatile(const volatile int); + +/// template remove_cv; +#define CheckRemoveCv(T) \ + RAD_S_ASSERT((is_same::type, std::remove_cv::type>::value)) + +CheckRemoveCv(int); +CheckRemoveCv(const int); +CheckRemoveCv(volatile int); +CheckRemoveCv(const volatile int); + +/// template remove_extent; +#define CheckRemoveExtent(T) \ + RAD_S_ASSERT( \ + (is_same::type, std::remove_extent::type>::value)) + +CheckRemoveExtent(int); +CheckRemoveExtent(int[2]); +CheckRemoveExtent(int[4][2]); +CheckRemoveExtent(int[][4][2]); +CheckRemoveExtent(int[]); + +/// template remove_all_extents; +#define CheckRemoveAllExtents(T) \ + RAD_S_ASSERT((is_same::type, \ + std::remove_all_extents::type>::value)) + +CheckRemoveAllExtents(int); +CheckRemoveAllExtents(int[2]); +CheckRemoveAllExtents(int[4][2]); +CheckRemoveAllExtents(int[][4][2]); +CheckRemoveAllExtents(int[]); + +/// template add_rvalue_reference; +#define CheckAddRvalueReference(T) \ + RAD_S_ASSERT((is_same::type, \ + std::add_rvalue_reference::type>::value)) + +CheckAddRvalueReference(int); +CheckAddRvalueReference(const volatile int); +CheckAddRvalueReference(int&); +CheckAddRvalueReference(int&&); +CheckAddRvalueReference(int*); +CheckAddRvalueReference(void*); + +/// template add_pointer; +#define CheckAddPointer(T) \ + RAD_S_ASSERT( \ + (is_same::type, std::add_pointer::type>::value)) + +CheckAddPointer(int); +CheckAddPointer(int*); +CheckAddPointer(int&); +CheckAddPointer(int&&); +CheckAddPointer(int[]); +CheckAddPointer(int[2]); +CheckAddPointer(void); +CheckAddPointer(void(int)); +CheckAddPointer(int (MemberFunctionTester::*)() const); + +/// template add_cv; +#define CheckAddCv(T) \ + RAD_S_ASSERT((is_same::type, std::add_cv::type>::value)) + +CheckAddCv(int); +CheckAddCv(const int); +CheckAddCv(volatile int); + +/// template add_const; +#define CheckAddConst(T) \ + RAD_S_ASSERT((is_same::type, std::add_const::type>::value)) + +CheckAddConst(int); +CheckAddConst(const int); +CheckAddConst(volatile int); + +/// template add_volatile; +#define CheckAddVolatile(T) \ + RAD_S_ASSERT( \ + (is_same::type, std::add_volatile::type>::value)) + +CheckAddVolatile(int); +CheckAddVolatile(const int); +CheckAddVolatile(volatile int); + +/// typename add_rvalue_reference::type declval() noexcept; +#define CheckDeclval(T) \ + RAD_S_ASSERT( \ + (is_same()), decltype(std::declval())>::value)) + +CheckDeclval(int); +CheckDeclval(const volatile int); +CheckDeclval(int&); +CheckDeclval(int&&); +CheckDeclval(int*); +CheckDeclval(void*); + +/// template is_void; +#define CheckIsVoid(T) RAD_S_ASSERT(is_void::value == std::is_void::value) + +CheckIsVoid(int); +CheckIsVoid(const volatile int); +CheckIsVoid(const int); +CheckIsVoid(volatile int&&); +CheckIsVoid(int*); +CheckIsVoid(void*); +CheckIsVoid(Derived()); + +/// template is_const; +#define CheckIsConst(T) \ + RAD_S_ASSERT(is_const::value == std::is_const::value) + +CheckIsConst(int); +CheckIsConst(const volatile int); +CheckIsConst(const int); +CheckIsConst(volatile int&&); +CheckIsConst(int*); +CheckIsConst(void*); +CheckIsConst(Derived()); + +/// template is_volatile; +#define CheckIsVolatile(T) \ + RAD_S_ASSERT(is_volatile::value == std::is_volatile::value) + +CheckIsVolatile(int); +CheckIsVolatile(const volatile int); +CheckIsVolatile(const int); +CheckIsVolatile(volatile int&&); +CheckIsVolatile(int*); +CheckIsVolatile(void*); +CheckIsVolatile(Derived()); + +/// template is_reference; +#define CheckIsReference(T) \ + RAD_S_ASSERT(is_reference::value == std::is_reference::value) + +CheckIsReference(int); +CheckIsReference(const volatile int); +CheckIsReference(int&); +CheckIsReference(int&&); +CheckIsReference(int*); +CheckIsReference(void*); +CheckIsReference(Derived()); + +/// template is_lvalue_reference; +#define CheckIsLvalueReference(T) \ + RAD_S_ASSERT(is_lvalue_reference::value == \ + std::is_lvalue_reference::value) + +CheckIsLvalueReference(int); +CheckIsLvalueReference(const volatile int); +CheckIsLvalueReference(int&); +CheckIsLvalueReference(int&&); +CheckIsLvalueReference(int*); +CheckIsLvalueReference(void*); +CheckIsLvalueReference(Derived()); + +/// template is_rvalue_reference; +#define CheckIsRvalueReference(T) \ + RAD_S_ASSERT(is_rvalue_reference::value == \ + std::is_rvalue_reference::value) + +CheckIsRvalueReference(int); +CheckIsRvalueReference(const volatile int); +CheckIsRvalueReference(int&); +CheckIsRvalueReference(int&&); +CheckIsRvalueReference(int*); +CheckIsRvalueReference(Derived()); + +/// template is_pointer; +#define CheckIsPointer(T) \ + RAD_S_ASSERT(is_pointer::value == std::is_pointer::value) + +CheckIsPointer(int(long)); +CheckIsPointer(int); +CheckIsPointer(std::function); +CheckIsPointer(int*); +CheckIsPointer(int&); +CheckIsPointer(int*&); +CheckIsPointer(decltype(nullptr)); +CheckIsPointer(void*); + +/// template is_null_pointer; +#define CheckIsNullPointer(T) \ + RAD_S_ASSERT(is_null_pointer::value == std::is_null_pointer::value) + +CheckIsNullPointer(int(long)); +CheckIsNullPointer(int); +CheckIsNullPointer(std::function); +CheckIsNullPointer(int*); +CheckIsNullPointer(int&); +CheckIsNullPointer(int*&); +CheckIsNullPointer(decltype(nullptr)); +CheckIsNullPointer(void*); + +/// template is_member_pointer; +#define CheckIsMemberPointer(T) \ + RAD_S_ASSERT(is_member_pointer::value == \ + std::is_member_pointer::value) + +CheckIsMemberPointer(int); +CheckIsMemberPointer(int&); +CheckIsMemberPointer(int&&); +CheckIsMemberPointer(int*); +CheckIsMemberPointer(const int); +CheckIsMemberPointer(void); +CheckIsMemberPointer(const char*); +CheckIsMemberPointer(float); +CheckIsMemberPointer(double); +CheckIsMemberPointer(wchar_t); +CheckIsMemberPointer(Enum8); +CheckIsMemberPointer(Base); +CheckIsMemberPointer(Union); +CheckIsMemberPointer(int(Base::*)); + +/// template is_array; +#define CheckIsArray(T) \ + RAD_S_ASSERT(is_array::value == std::is_array::value) + +CheckIsArray(int); +CheckIsArray(int&); +CheckIsArray(int&&); +CheckIsArray(int*); +CheckIsArray(const int); +CheckIsArray(const volatile int&); +CheckIsArray(void); +CheckIsArray(const volatile void); +CheckIsArray(int(long)); +CheckIsArray(long[]); +CheckIsArray(long[3]); +CheckIsArray(long[3][3][4]); +CheckIsArray(long[][3][4]); + +/// template is_enum; +#define CheckIsEnum(T) RAD_S_ASSERT(is_enum::value == std::is_enum::value) + +CheckIsEnum(int); +CheckIsEnum(int&); +CheckIsEnum(int&&); +CheckIsEnum(int*); +CheckIsEnum(const int); +CheckIsEnum(void); +CheckIsEnum(const char*); +CheckIsEnum(float); +CheckIsEnum(double); +CheckIsEnum(wchar_t); +CheckIsEnum(Enum8); +CheckIsEnum(Base); +CheckIsEnum(Union); + +/// template is_function; +#define CheckIsFunction(T) \ + RAD_S_ASSERT(is_function::value == std::is_function::value) + +CheckIsFunction(int(long)); +CheckIsFunction(int); +CheckIsFunction(std::function); +CheckIsFunction(decltype(PlainFunction)); +CheckIsFunction(MemberFunctionTester()); +CheckIsFunction(MemberFunctionTester); +CheckIsFunction(decltype(MemberFunctionTester::Static)); +CheckIsFunction(decltype(&MemberFunctionTester::Member)); +#if RAD_CPP20 +CheckIsFunction(decltype([] {})); +#endif + +/// template is_integral; +#define CheckIsIntegral(T) \ + RAD_S_ASSERT(is_integral::value == std::is_integral::value) + +CheckIsIntegral(int); +CheckIsIntegral(int&); +CheckIsIntegral(int&&); +CheckIsIntegral(int*); +CheckIsIntegral(const int); +CheckIsIntegral(void); +CheckIsIntegral(const char*); +CheckIsIntegral(float); +CheckIsIntegral(double); +CheckIsIntegral(wchar_t); +CheckIsIntegral(Enum8); +CheckIsIntegral(Base); +CheckIsIntegral(Union); + +/// template is_floating_point; +#define CheckIsFloatingPoint(T) \ + RAD_S_ASSERT(is_floating_point::value == \ + std::is_floating_point::value) + +CheckIsFloatingPoint(int); +CheckIsFloatingPoint(int&); +CheckIsFloatingPoint(int&&); +CheckIsFloatingPoint(int*); +CheckIsFloatingPoint(const int); +CheckIsFloatingPoint(void); +CheckIsFloatingPoint(const char*); +CheckIsFloatingPoint(float); +CheckIsFloatingPoint(double); +CheckIsFloatingPoint(Enum8); +CheckIsFloatingPoint(Base); +CheckIsFloatingPoint(Union); + +/// template is_arithmetic; +#define CheckIsArithmetic(T) \ + RAD_S_ASSERT(is_arithmetic::value == std::is_arithmetic::value) + +CheckIsArithmetic(int); +CheckIsArithmetic(int&); +CheckIsArithmetic(int&&); +CheckIsArithmetic(int*); +CheckIsArithmetic(const int); +CheckIsArithmetic(void); +CheckIsArithmetic(const char*); +CheckIsArithmetic(Enum8); +CheckIsArithmetic(Base); +CheckIsArithmetic(Union); + +/// template is_scalar; +#define CheckIsScalar(T) \ + RAD_S_ASSERT(is_scalar::value == std::is_scalar::value) + +CheckIsScalar(int); +CheckIsScalar(int&); +CheckIsScalar(int&&); +CheckIsScalar(int*); +CheckIsScalar(const int); +CheckIsScalar(void); +CheckIsScalar(const char*); +CheckIsScalar(Enum8); +CheckIsScalar(Base); +CheckIsScalar(Union); + +/// template is_empty; +#define CheckIsEmpty(T) \ + RAD_S_ASSERT(is_empty::value == std::is_empty::value) + +CheckIsEmpty(int); +CheckIsEmpty(int&); +CheckIsEmpty(int&&); +CheckIsEmpty(int*); +CheckIsEmpty(const int); +CheckIsEmpty(void); +CheckIsEmpty(Base); +CheckIsEmpty(Derived); +CheckIsEmpty(VirtualBase); +CheckIsEmpty(PureVirtualBase); +CheckIsEmpty(VirtualDerivedEmpty); +CheckIsEmpty(DerivedPureVirtual); +CheckIsEmpty(EmptyUnion); +CheckIsEmpty(ClassWithEmptyUnion); +CheckIsEmpty(Union); + +/// template is_polymorphic; +#define CheckIsPolymorphic(T) \ + RAD_S_ASSERT(is_polymorphic::value == std::is_polymorphic::value) + +CheckIsPolymorphic(int); +CheckIsPolymorphic(int&); +CheckIsPolymorphic(int&&); +CheckIsPolymorphic(int*); +CheckIsPolymorphic(const int); +CheckIsPolymorphic(void); +CheckIsPolymorphic(Base); +CheckIsPolymorphic(Derived); +CheckIsPolymorphic(VirtualBase); +CheckIsPolymorphic(PureVirtualBase); +CheckIsPolymorphic(VirtualDerivedEmpty); +CheckIsPolymorphic(DerivedPureVirtual); + +/// template is_assignable; +#define CheckIsAssignable(T) \ + RAD_S_ASSERT( \ + (is_assignable::value == std::is_assignable::value)) + +CheckIsAssignable(NoThrow); +CheckIsAssignable(Throw); +CheckIsAssignable(NoOps); +CheckIsAssignable(int); +CheckIsAssignable(int&); +CheckIsAssignable(int&&); +CheckIsAssignable(int*); +CheckIsAssignable(const int); +CheckIsAssignable(void); + +/// template is_constructible; +#define CheckIsConstructible(T, U) \ + RAD_S_ASSERT( \ + (is_constructible::value == std::is_constructible::value)) + +CheckIsConstructible(NoThrow, int); +CheckIsConstructible(Throw, int); +CheckIsConstructible(NoOps, int); +CheckIsConstructible(int, int); +CheckIsConstructible(int&, int); +CheckIsConstructible(int&&, int); +CheckIsConstructible(int*, int); +CheckIsConstructible(const int, int); +CheckIsConstructible(void, int); + +/// template is_copy_assignable; +#define CheckIsCopyAssignable(T) \ + RAD_S_ASSERT(is_copy_assignable::value == \ + std::is_copy_assignable::value) + +CheckIsCopyAssignable(NoThrow); +CheckIsCopyAssignable(Throw); +CheckIsCopyAssignable(NoOps); +CheckIsCopyAssignable(int); +CheckIsCopyAssignable(int&); +CheckIsCopyAssignable(int&&); +CheckIsCopyAssignable(int*); +CheckIsCopyAssignable(const int); +CheckIsCopyAssignable(void); + +/// template is_copy_constructible; +#define CheckIsCopyConstructible(T) \ + RAD_S_ASSERT(is_copy_constructible::value == \ + std::is_copy_constructible::value) + +CheckIsCopyConstructible(NoThrow); +CheckIsCopyConstructible(Throw); +CheckIsCopyConstructible(NoOps); +CheckIsCopyConstructible(int); +CheckIsCopyConstructible(int&); +CheckIsCopyConstructible(int&&); +CheckIsCopyConstructible(int*); +CheckIsCopyConstructible(const int); +CheckIsCopyConstructible(void); + +/// template is_default_constructible; +#define CheckIsDefaultConstructible(T) \ + RAD_S_ASSERT(is_default_constructible::value == \ + std::is_default_constructible::value) + +CheckIsDefaultConstructible(NoThrow); +CheckIsDefaultConstructible(Throw); +CheckIsDefaultConstructible(NoOps); +CheckIsDefaultConstructible(int); +CheckIsDefaultConstructible(int&); +CheckIsDefaultConstructible(int&&); +CheckIsDefaultConstructible(int*); +CheckIsDefaultConstructible(const int); +CheckIsDefaultConstructible(void); + +/// template is_destructible; +#define CheckIsDestructible(T) \ + RAD_S_ASSERT(is_destructible::value == std::is_destructible::value) + +CheckIsDestructible(NoThrow); +CheckIsDestructible(Throw); +CheckIsDestructible(NoOps); +CheckIsDestructible(int); +CheckIsDestructible(int&); +CheckIsDestructible(int&&); +CheckIsDestructible(int*); +CheckIsDestructible(const int); +CheckIsDestructible(const volatile int&); +CheckIsDestructible(void); +CheckIsDestructible(const volatile void); +CheckIsDestructible(int(long)); +CheckIsDestructible(long[]); +CheckIsDestructible(long[3]); +CheckIsDestructible(long[3][3][4]); +CheckIsDestructible(long[][3][4]); + +/// template is_move_assignable; +#define CheckIsMoveAssignable(T) \ + RAD_S_ASSERT(is_move_assignable::value == \ + std::is_move_assignable::value) + +CheckIsMoveAssignable(NoThrow); +CheckIsMoveAssignable(Throw); +CheckIsMoveAssignable(NoOps); +CheckIsMoveAssignable(int); +CheckIsMoveAssignable(int&); +CheckIsMoveAssignable(int&&); +CheckIsMoveAssignable(int*); +CheckIsMoveAssignable(const int); +CheckIsMoveAssignable(void); + +/// template is_move_constructible; +#define CheckIsMoveConstructible(T) \ + RAD_S_ASSERT(is_move_constructible::value == \ + std::is_move_constructible::value) + +CheckIsMoveConstructible(NoThrow); +CheckIsMoveConstructible(Throw); +CheckIsMoveConstructible(NoOps); +CheckIsMoveConstructible(int); +CheckIsMoveConstructible(int&); +CheckIsMoveConstructible(int&&); +CheckIsMoveConstructible(int*); +CheckIsMoveConstructible(const int); +CheckIsMoveConstructible(void); + +/// template is_trivially_assignable; +#define CheckIsTriviallyAssignable(T) \ + RAD_S_ASSERT((is_trivially_assignable::value == \ + std::is_trivially_assignable::value)) + +CheckIsTriviallyAssignable(Trivial); +CheckIsTriviallyAssignable(NonTrivial); +CheckIsTriviallyAssignable(NoOps); +CheckIsTriviallyAssignable(int); +CheckIsTriviallyAssignable(int&); +CheckIsTriviallyAssignable(int&&); +CheckIsTriviallyAssignable(int*); +CheckIsTriviallyAssignable(const int); +CheckIsTriviallyAssignable(void); + +/// template is_trivially_constructible; +#define CheckIsTriviallyConstructible(T, U) \ + RAD_S_ASSERT((is_trivially_constructible::value == \ + std::is_trivially_constructible::value)) + +CheckIsTriviallyConstructible(Trivial, int); +CheckIsTriviallyConstructible(NonTrivial, int); +CheckIsTriviallyConstructible(NoOps, int); +CheckIsTriviallyConstructible(int, int); +CheckIsTriviallyConstructible(int&, int); +CheckIsTriviallyConstructible(int&&, int); +CheckIsTriviallyConstructible(int*, int); +CheckIsTriviallyConstructible(const int, int); +CheckIsTriviallyConstructible(void, int); + +/// template is_trivially_copy_assignable; +#define CheckIsTriviallyCopyAssignable(T) \ + RAD_S_ASSERT(is_trivially_copy_assignable::value == \ + std::is_trivially_copy_assignable::value) + +CheckIsTriviallyCopyAssignable(Trivial); +CheckIsTriviallyCopyAssignable(NonTrivial); +CheckIsTriviallyCopyAssignable(NoOps); +CheckIsTriviallyCopyAssignable(int); +CheckIsTriviallyCopyAssignable(int&); +CheckIsTriviallyCopyAssignable(int&&); +CheckIsTriviallyCopyAssignable(int*); +CheckIsTriviallyCopyAssignable(const int); +CheckIsTriviallyCopyAssignable(void); + +/// template is_trivially_copy_constructible; +#define CheckIsTriviallyCopyConstructible(T) \ + RAD_S_ASSERT(is_trivially_copy_constructible::value == \ + std::is_trivially_copy_constructible::value) + +CheckIsTriviallyCopyConstructible(Trivial); +CheckIsTriviallyCopyConstructible(NonTrivial); +CheckIsTriviallyCopyConstructible(NoOps); +CheckIsTriviallyCopyConstructible(int); +CheckIsTriviallyCopyConstructible(int&); +CheckIsTriviallyCopyConstructible(int&&); +CheckIsTriviallyCopyConstructible(int*); +CheckIsTriviallyCopyConstructible(const int); +CheckIsTriviallyCopyConstructible(void); + +/// template is_trivially_default_constructible; +#define CheckIsTriviallyDefaultConstructible(T) \ + RAD_S_ASSERT(is_trivially_default_constructible::value == \ + std::is_trivially_default_constructible::value) + +CheckIsTriviallyDefaultConstructible(Trivial); +CheckIsTriviallyDefaultConstructible(NonTrivial); +CheckIsTriviallyDefaultConstructible(NoOps); +CheckIsTriviallyDefaultConstructible(int); +CheckIsTriviallyDefaultConstructible(int&); +CheckIsTriviallyDefaultConstructible(int&&); +CheckIsTriviallyDefaultConstructible(int*); +CheckIsTriviallyDefaultConstructible(const int); +CheckIsTriviallyDefaultConstructible(void); + +/// template is_trivially_destructible; +#define CheckIsTriviallyDestructible(T) \ + RAD_S_ASSERT(is_trivially_destructible::value == \ + std::is_trivially_destructible::value) + +CheckIsTriviallyDestructible(Trivial); +CheckIsTriviallyDestructible(NonTrivial); +CheckIsTriviallyDestructible(NoOps); +CheckIsTriviallyDestructible(int); +CheckIsTriviallyDestructible(int&); +CheckIsTriviallyDestructible(int&&); +CheckIsTriviallyDestructible(int*); +CheckIsTriviallyDestructible(const int); +CheckIsTriviallyDestructible(void); + +/// template is_trivially_move_assignable; +#define CheckIsTriviallyMoveAssignable(T) \ + RAD_S_ASSERT(is_trivially_move_assignable::value == \ + std::is_trivially_move_assignable::value) + +CheckIsTriviallyMoveAssignable(Trivial); +CheckIsTriviallyMoveAssignable(NonTrivial); +CheckIsTriviallyMoveAssignable(NoOps); +CheckIsTriviallyMoveAssignable(int); +CheckIsTriviallyMoveAssignable(int&); +CheckIsTriviallyMoveAssignable(int&&); +CheckIsTriviallyMoveAssignable(int*); +CheckIsTriviallyMoveAssignable(const int); +CheckIsTriviallyMoveAssignable(void); + +/// template is_trivially_move_constructible; +#define CheckIsTriviallyMoveConstructible(T) \ + RAD_S_ASSERT(is_trivially_move_constructible::value == \ + std::is_trivially_move_constructible::value) + +CheckIsTriviallyMoveConstructible(Trivial); +CheckIsTriviallyMoveConstructible(NonTrivial); +CheckIsTriviallyMoveConstructible(NoOps); +CheckIsTriviallyMoveConstructible(int); +CheckIsTriviallyMoveConstructible(int&); +CheckIsTriviallyMoveConstructible(int&&); +CheckIsTriviallyMoveConstructible(int*); +CheckIsTriviallyMoveConstructible(const int); +CheckIsTriviallyMoveConstructible(void); + +/// template is_nothrow_assignable; +#define CheckIsNoThrowAssignable(T) \ + RAD_S_ASSERT((is_nothrow_assignable::value == \ + std::is_nothrow_assignable::value)) + +CheckIsNoThrowAssignable(NoThrow); +CheckIsNoThrowAssignable(Throw); +CheckIsNoThrowAssignable(NoOps); +CheckIsNoThrowAssignable(int); +CheckIsNoThrowAssignable(int&); +CheckIsNoThrowAssignable(int&&); +CheckIsNoThrowAssignable(int*); +CheckIsNoThrowAssignable(const int); +CheckIsNoThrowAssignable(void); + +/// template is_nothrow_constructible; +#define CheckIsNoThrowConstructible(T, U) \ + RAD_S_ASSERT((is_nothrow_constructible::value == \ + std::is_nothrow_constructible::value)) + +CheckIsNoThrowConstructible(NoThrow, int); +CheckIsNoThrowConstructible(Throw, int); +CheckIsNoThrowConstructible(NoOps, int); +CheckIsNoThrowConstructible(int, int); +CheckIsNoThrowConstructible(int&, int); +CheckIsNoThrowConstructible(int&&, int); +CheckIsNoThrowConstructible(int*, int); +CheckIsNoThrowConstructible(const int, int); +CheckIsNoThrowConstructible(void, int); + +/// template is_nothrow_copy_assignable; +#define CheckIsNoThrowCopyAssignable(T) \ + RAD_S_ASSERT(is_nothrow_copy_assignable::value == \ + std::is_nothrow_copy_assignable::value) + +CheckIsNoThrowCopyAssignable(NoThrow); +CheckIsNoThrowCopyAssignable(Throw); +CheckIsNoThrowCopyAssignable(NoOps); +CheckIsNoThrowCopyAssignable(int); +CheckIsNoThrowCopyAssignable(int&); +CheckIsNoThrowCopyAssignable(int&&); +CheckIsNoThrowCopyAssignable(int*); +CheckIsNoThrowCopyAssignable(const int); +CheckIsNoThrowCopyAssignable(void); + +/// template is_nothrow_copy_constructible; +#define CheckIsNoThrowCopyConstructible(T) \ + RAD_S_ASSERT(is_nothrow_copy_constructible::value == \ + std::is_nothrow_copy_constructible::value) + +CheckIsNoThrowCopyConstructible(NoThrow); +CheckIsNoThrowCopyConstructible(Throw); +CheckIsNoThrowCopyConstructible(NoOps); +CheckIsNoThrowCopyConstructible(int); +CheckIsNoThrowCopyConstructible(int&); +CheckIsNoThrowCopyConstructible(int&&); +CheckIsNoThrowCopyConstructible(int*); +CheckIsNoThrowCopyConstructible(const int); +CheckIsNoThrowCopyConstructible(void); + +/// template is_nothrow_default_constructible; +#define CheckIsNoThrowDefaultConstructible(T) \ + RAD_S_ASSERT(is_nothrow_default_constructible::value == \ + std::is_nothrow_default_constructible::value) + +CheckIsNoThrowDefaultConstructible(NoThrow); +CheckIsNoThrowDefaultConstructible(Throw); +CheckIsNoThrowDefaultConstructible(NoOps); +CheckIsNoThrowDefaultConstructible(int); +CheckIsNoThrowDefaultConstructible(int&); +CheckIsNoThrowDefaultConstructible(int&&); +CheckIsNoThrowDefaultConstructible(int*); +CheckIsNoThrowDefaultConstructible(const int); +CheckIsNoThrowDefaultConstructible(void); + +/// template is_nothrow_destructible; +#define CheckIsNoThrowDestructible(T) \ + RAD_S_ASSERT(is_nothrow_destructible::value == \ + std::is_nothrow_destructible::value) + +CheckIsNoThrowDestructible(NoThrow); +CheckIsNoThrowDestructible(Throw); +CheckIsNoThrowDestructible(NoOps); +CheckIsNoThrowDestructible(int); +CheckIsNoThrowDestructible(int&); +CheckIsNoThrowDestructible(int&&); +CheckIsNoThrowDestructible(int*); +CheckIsNoThrowDestructible(const int); +CheckIsNoThrowDestructible(const volatile int&); +CheckIsNoThrowDestructible(void); +CheckIsNoThrowDestructible(const volatile void); +CheckIsNoThrowDestructible(int(long)); +CheckIsNoThrowDestructible(long[]); +CheckIsNoThrowDestructible(long[3]); +CheckIsNoThrowDestructible(long[3][3][4]); +CheckIsNoThrowDestructible(long[][3][4]); + +/// template is_nothrow_move_assignable; +#define CheckIsNoThrowMoveAssignable(T) \ + RAD_S_ASSERT(is_nothrow_move_assignable::value == \ + std::is_nothrow_move_assignable::value) + +CheckIsNoThrowMoveAssignable(NoThrow); +CheckIsNoThrowMoveAssignable(Throw); +CheckIsNoThrowMoveAssignable(NoOps); +CheckIsNoThrowMoveAssignable(int); +CheckIsNoThrowMoveAssignable(int&); +CheckIsNoThrowMoveAssignable(int&&); +CheckIsNoThrowMoveAssignable(int*); +CheckIsNoThrowMoveAssignable(const int); +CheckIsNoThrowMoveAssignable(void); + +/// template is_nothrow_move_constructible; +#define CheckIsNoThrowMoveConstructible(T) \ + RAD_S_ASSERT(is_nothrow_move_constructible::value == \ + std::is_nothrow_move_constructible::value) + +CheckIsNoThrowMoveConstructible(NoThrow); +CheckIsNoThrowMoveConstructible(Throw); +CheckIsNoThrowMoveConstructible(NoOps); +CheckIsNoThrowMoveConstructible(int); +CheckIsNoThrowMoveConstructible(int&); +CheckIsNoThrowMoveConstructible(int&&); +CheckIsNoThrowMoveConstructible(int*); +CheckIsNoThrowMoveConstructible(const int); +CheckIsNoThrowMoveConstructible(void); + +/// template is_trivial; +#define CheckIsTrivial(T) \ + RAD_S_ASSERT(is_trivial::value == std::is_trivial::value) + +CheckIsTrivial(int); +CheckIsTrivial(int&); +CheckIsTrivial(const int&); +CheckIsTrivial(int*); +CheckIsTrivial(void); +CheckIsTrivial(Trivial); +CheckIsTrivial(NonTrivial); + +/// template is_signed; +#define CheckIsSigned(T) \ + RAD_S_ASSERT(is_signed::value == std::is_signed::value) + +CheckIsSigned(int); +CheckIsSigned(unsigned int); +CheckIsSigned(signed char); +CheckIsSigned(char); +CheckIsSigned(unsigned char); +CheckIsSigned(wchar_t); +CheckIsSigned(Base); +CheckIsSigned(float); +CheckIsSigned(void(int)); + +/// template is_convertible; +#define CheckIsConvertible(from, to) \ + RAD_S_ASSERT((is_convertible::value == \ + std::is_convertible::value)) + +CheckIsConvertible(void, void); +CheckIsConvertible(int, long); +CheckIsConvertible(long, int); +CheckIsConvertible(Derived, Base); +CheckIsConvertible(Base, Derived); +CheckIsConvertible(Derived*, Base*); +CheckIsConvertible(Convertable, Convert); +CheckIsConvertible(Convert, Convertable); +CheckIsConvertible(Convertable*, Convert*); +CheckIsConvertible(Convert*, Convertable*); +CheckIsConvertible(Derived, AlwaysConvertable); +CheckIsConvertible(int[3], int[3]); +CheckIsConvertible(int[3], long[3]); +CheckIsConvertible(long[3], int[3]); +CheckIsConvertible(int(int), void); +CheckIsConvertible(void, int(int)); + +/// template has_virtual_destructor; +#define CheckHasVirtualDestructor(T) \ + RAD_S_ASSERT(has_virtual_destructor::value == \ + std::has_virtual_destructor::value) + +CheckHasVirtualDestructor(Derived); +CheckHasVirtualDestructor(Base); +CheckHasVirtualDestructor(DerivedPureVirtual); + +/// template make_unsigned; +#define CheckMakeUnsigned(T) \ + RAD_S_ASSERT(( \ + is_same::type, std::make_unsigned::type>::value)); \ + RAD_S_ASSERT((is_same::type, \ + std::make_unsigned::type>::value)); \ + RAD_S_ASSERT((is_same::type, \ + std::make_unsigned::type>::value)); \ + RAD_S_ASSERT((is_same::type, \ + std::make_unsigned::type>::value)) + +CheckMakeUnsigned(signed char); +CheckMakeUnsigned(unsigned char); +CheckMakeUnsigned(signed short); +CheckMakeUnsigned(unsigned short); +CheckMakeUnsigned(signed int); +CheckMakeUnsigned(unsigned int); +CheckMakeUnsigned(signed long); +CheckMakeUnsigned(unsigned long); +CheckMakeUnsigned(signed long long); +CheckMakeUnsigned(unsigned long long); + +CheckMakeUnsigned(char); +CheckMakeUnsigned(wchar_t); +CheckMakeUnsigned(char16_t); +CheckMakeUnsigned(char32_t); + +CheckMakeUnsigned(Enum8); +CheckMakeUnsigned(Enum16); +CheckMakeUnsigned(Enum32); +CheckMakeUnsigned(OldEnum); + +// TODO: The compilers agree that this should be a 64 bit value, but they do +// not agree on if that should mean unsigned long or unsigned long long, nor +// do the compilers agree on whether uint64_t should be unsigned long or +// unsigned long long +// CheckMakeUnsigned(Enum64); + +#if RAD_CPP20 +CheckMakeUnsigned(char8_t); +#endif + +/// template decay; +#define CheckDecay(T) \ + RAD_S_ASSERT((is_same::type, std::decay::type>::value)) + +CheckDecay(int); +CheckDecay(int&); +CheckDecay(int&&); +CheckDecay(const int&); +CheckDecay(int[2]); +CheckDecay(int[4][2]); +CheckDecay(int(int)); + +namespace meta +{ + +RAD_S_ASSERT(Types::size() == 4); + +RAD_S_ASSERT((is_same::Type>::value)); +RAD_S_ASSERT((is_same::Type>::value)); +RAD_S_ASSERT((is_same::Type>::value)); + +RAD_S_ASSERT((is_same::Type>::value)); +RAD_S_ASSERT((is_same::Type>::value)); +RAD_S_ASSERT((is_same::Type>::value)); +RAD_S_ASSERT((is_same::Type>::value)); + +RAD_S_ASSERT((Contains::Type::value)); +RAD_S_ASSERT((Contains::Type::value)); +RAD_S_ASSERT((Contains::Type::value)); +RAD_S_ASSERT((!Contains::Type::value)); + +} // namespace meta + +} // namespace rad