diff --git a/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp b/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp index 6d8d9de..8dd3c33 100644 --- a/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/MiscellaneousTesting.cpp @@ -2,6 +2,7 @@ #include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/Compare.h" +#include "Miscellaneous/VarArgs.h" NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) @@ -13,6 +14,7 @@ void TestMiscellaneous() { TestAssertionMacros(); TestCompare(); + TestVarArgs(); } NAMESPACE_UNNAMED_BEGIN @@ -220,6 +222,69 @@ void TestCompare() always_check(SynthThreeWayCompare(FTestSynth( 0), FTestSynth(-1)) == weak_ordering::greater); } +NAMESPACE_UNNAMED_BEGIN + +enum class ETestVarArgs +{ + A = 0xA, + B = 0xB, +}; + +struct FTestVarArgs +{ + int16 A; + float32 B; + + friend bool operator==(const FTestVarArgs& LHS, const FTestVarArgs& RHS) { return LHS.A == RHS.A && LHS.B == RHS.B; } +}; + +void VARARGS TestVarArgs(int32 Count, ...) +{ + VARARGS_ACCESS_BEGIN(Context, Count); + +// always_check(VARARGS_ACCESS(Context, bool) == true); +// always_check(VARARGS_ACCESS(Context, char) == 2); +// always_check(VARARGS_ACCESS(Context, short) == 3); + always_check(VARARGS_ACCESS(Context, int) == 4); + always_check(VARARGS_ACCESS(Context, long long) == 5); + +// always_check(VARARGS_ACCESS(Context, float) == 6.0f); + always_check(VARARGS_ACCESS(Context, double) == 7.0 ); + always_check(VARARGS_ACCESS(Context, long double) == 8.0l); + +// always_check(VARARGS_ACCESS(Context, nullptr_t) == nullptr); + always_check(VARARGS_ACCESS(Context, void*) == nullptr); + always_check(VARARGS_ACCESS(Context, int32 FTestVarArgs::*) == nullptr); + + always_check(VARARGS_ACCESS(Context, ETestVarArgs) == ETestVarArgs::B); + always_check(VARARGS_ACCESS(Context, FTestVarArgs) == FTestVarArgs({ 404, 5.0f })); + + VARARGS_ACCESS_END(Context); +}; + +NAMESPACE_UNNAMED_END + +void TestVarArgs() +{ + TestVarArgs + ( + 7 - 5, +// true, +// static_cast< char>(2), +// static_cast< short>(3), + static_cast< int>(4), + static_cast(5), +// 6.0f, + 7.0, + 8.0l, +// nullptr, + static_cast(nullptr), + static_cast(nullptr), + ETestVarArgs::B, + FTestVarArgs({ 404, 5.0f }) + ); +} + NAMESPACE_END(Testing) NAMESPACE_MODULE_END(Utility) diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/VarArgs.h b/Redcraft.Utility/Source/Public/Miscellaneous/VarArgs.h new file mode 100644 index 0000000..9442178 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Miscellaneous/VarArgs.h @@ -0,0 +1,46 @@ +#pragma once + +#include "CoreTypes.h" +#include "TypeTraits/TypeTraits.h" + +#include + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +NAMESPACE_PRIVATE_BEGIN + +template +struct TVarArgsAssert +{ + static_assert(CArithmetic || CEnum || CPointer || CMemberPointer || CClass, "The type must be arithmetic, enum, pointer, member pointer, or class"); + static_assert(!CNullPointer, "The 'nullptr_t' is promoted to 'void*' when passed through '...'"); + static_assert(!CSameAs, "The 'float' is promoted to 'double' when passed through '...'"); + static_assert(!CSameAs, "The 'bool' is promoted to 'int' when passed through '...'"); + static_assert(!CSameAs, "The 'char' is promoted to 'int' when passed through '...'"); + static_assert(!CSameAs, "The 'short' is promoted to 'int' when passed through '...'"); + static_assert(CSameAs>, "The 'const' and 'volatile' qualifiers are removed when passed through '...'"); + static_assert(!CEnum || CScopedEnum, "The unscoped enum is promoted to 'int' when passed through '...'"); + static_assert(!CClass || CTriviallyCopyable, "The non-trivially copyable class is not supported"); +}; + +template inline constexpr TVarArgsAssert VarArgsAssert{ }; + +NAMESPACE_PRIVATE_END + +/** Enables access to variadic function arguments. */ +#define VARARGS_ACCESS_BEGIN(ContextName, NamedParam) NAMESPACE_STD::va_list ContextName; va_start(ContextName, NamedParam) + +/** Makes a copy of the variadic function arguments. */ +#define VARARGS_ACCESS_COPY(ContextName, ContextSource) NAMESPACE_STD::va_list ContextName; va_copy(ContextName, ContextSource) + +/** Accesses the next variadic function argument. */ +#define VARARGS_ACCESS(ContextName, Type) (NAMESPACE_PRIVATE::VarArgsAssert, va_arg(ContextName, Type)) + +/** Ends traversal of the variadic function arguments. */ +#define VARARGS_ACCESS_END(ContextName) va_end(ContextName) + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Public/Testing/MiscellaneousTesting.h b/Redcraft.Utility/Source/Public/Testing/MiscellaneousTesting.h index a11c3b4..e629c4a 100644 --- a/Redcraft.Utility/Source/Public/Testing/MiscellaneousTesting.h +++ b/Redcraft.Utility/Source/Public/Testing/MiscellaneousTesting.h @@ -11,6 +11,7 @@ NAMESPACE_BEGIN(Testing) REDCRAFTUTILITY_API void TestMiscellaneous(); REDCRAFTUTILITY_API void TestAssertionMacros(); REDCRAFTUTILITY_API void TestCompare(); +REDCRAFTUTILITY_API void TestVarArgs(); NAMESPACE_END(Testing)