diff --git a/Redcraft.Utility/Source/Private/Testing/StringTesting.cpp b/Redcraft.Utility/Source/Private/Testing/StringTesting.cpp index 6bcb1fb..fe516e8 100644 --- a/Redcraft.Utility/Source/Private/Testing/StringTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/StringTesting.cpp @@ -560,6 +560,26 @@ void TestStringConversion() { auto Test = [](TInPlaceType) { + always_check(TString::Format(LITERAL(T, "#{}#"), true ) == LITERAL(T, "#True#" )); + always_check(TString::Format(LITERAL(T, "#{}#"), false) == LITERAL(T, "#False#")); + + always_check(TString::Format(LITERAL(T, "#{}#"), +0) == LITERAL(T, "#0#")); + always_check(TString::Format(LITERAL(T, "#{}#"), 0) == LITERAL(T, "#0#")); + always_check(TString::Format(LITERAL(T, "#{}#"), -0) == LITERAL(T, "#0#")); + + always_check(TString::Format(LITERAL(T, "#{}#"), 42) == LITERAL(T, "#42#")); + + always_check(TString::Format(LITERAL(T, "#{}#"), +0.0) == LITERAL(T, "#0.000000#")); + always_check(TString::Format(LITERAL(T, "#{}#"), 0.0) == LITERAL(T, "#0.000000#")); + always_check(TString::Format(LITERAL(T, "#{}#"), -0.0) == LITERAL(T, "#-0.000000#")); + + always_check(TString::Format(LITERAL(T, "#{}#"), 3.140000) == LITERAL(T, "#3.140000#")); + + always_check(TString::Format(LITERAL(T, "#{}#"), +NAMESPACE_STD::numeric_limits::infinity()) == LITERAL(T, "#Infinity#")); + always_check(TString::Format(LITERAL(T, "#{}#"), -NAMESPACE_STD::numeric_limits::infinity()) == LITERAL(T, "#-Infinity#")); + always_check(TString::Format(LITERAL(T, "#{}#"), +NAMESPACE_STD::numeric_limits::quiet_NaN()) == LITERAL(T, "#NaN#")); + always_check(TString::Format(LITERAL(T, "#{}#"), -NAMESPACE_STD::numeric_limits::quiet_NaN()) == LITERAL(T, "#-NaN#")); + auto CheckParseArithmetic = [](TStringView View, U Result) { U Object; diff --git a/Redcraft.Utility/Source/Public/String/Conversion.h.inl b/Redcraft.Utility/Source/Public/String/Conversion.h.inl index 9e1a837..935d83b 100644 --- a/Redcraft.Utility/Source/Public/String/Conversion.h.inl +++ b/Redcraft.Utility/Source/Public/String/Conversion.h.inl @@ -44,6 +44,78 @@ struct TStringHelper return false; } + else if (Fmt.IsEmpty()) + { + if constexpr (CArithmetic) + { + constexpr const T* DigitToChar = LITERAL(T, "9876543210123456789"); + constexpr size_t ZeroIndex = 9; + + if constexpr (CSameAs) + { + Result += Object ? LITERAL(T, "True") : LITERAL(T, "False"); + + return true; + } + + else if constexpr (CIntegral) + { + U Value = Object; + + const bool bNegative = Object < 0; + + constexpr size_t BufferSize = 32; + + T Buffer[BufferSize]; + + size_t Index = BufferSize; + + do Buffer[--Index] = DigitToChar[ZeroIndex + Value % 10]; while (Value /= 10); + + if (bNegative) Buffer[--Index] = LITERAL(T, '-'); + + const T* Begin = Buffer + Index; + const T* End = Buffer + BufferSize; + + Result.Append(Begin, End); + + return true; + } + + else if constexpr (CFloatingPoint) + { + if (NAMESPACE_STD::isinf(Object) && !NAMESPACE_STD::signbit(Object)) { Result += LITERAL(T, "Infinity"); return true; } + if (NAMESPACE_STD::isinf(Object) && NAMESPACE_STD::signbit(Object)) { Result += LITERAL(T, "-Infinity"); return true; } + + if (NAMESPACE_STD::isnan(Object) && !NAMESPACE_STD::signbit(Object)) { Result += LITERAL(T, "NaN"); return true; } + if (NAMESPACE_STD::isnan(Object) && NAMESPACE_STD::signbit(Object)) { Result += LITERAL(T, "-NaN"); return true; } + + U Value = NAMESPACE_STD::round(Object * static_cast(1e6)); + + const bool bNegative = NAMESPACE_STD::signbit(Object); + + TString> Buffer; + + for (size_t Index = 0; Index <= 6 || static_cast(Value) != 0; ++Index) + { + Buffer += DigitToChar[ZeroIndex + static_cast(NAMESPACE_STD::fmod(Value, 10))]; + + if (Index == 5) Buffer += LITERAL(T, '.'); + + Value /= 10; + } + + if (bNegative) Buffer += LITERAL(T, '-'); + + Result.Append(Buffer.RBegin(), Buffer.REnd()); + + return true; + } + + else static_assert(sizeof(U) == -1, "Unsupported arithmetic type"); + } + } + return false; }