Compare commits
3 Commits
09bbcecc28
...
fe60fc33e0
Author | SHA1 | Date | |
---|---|---|---|
fe60fc33e0 | |||
49feb0b12b | |||
f8ef1da107 |
@ -77,13 +77,13 @@ void TestChar()
|
|||||||
always_check(TChar<T>::ToLower(LITERAL(T, 'i')) == LITERAL(T, 'i'));
|
always_check(TChar<T>::ToLower(LITERAL(T, 'i')) == LITERAL(T, 'i'));
|
||||||
always_check(TChar<T>::ToUpper(LITERAL(T, 'l')) == LITERAL(T, 'L'));
|
always_check(TChar<T>::ToUpper(LITERAL(T, 'l')) == LITERAL(T, 'L'));
|
||||||
|
|
||||||
always_check(0x0 == TChar<T>::ToDigit(LITERAL(T, '0')));
|
always_check(0x0 == TChar<T>::ToDigit(LITERAL(T, '0'), 16));
|
||||||
always_check(0xF == TChar<T>::ToDigit(LITERAL(T, 'f')));
|
always_check(0xF == TChar<T>::ToDigit(LITERAL(T, 'f'), 16));
|
||||||
always_check(0xF == TChar<T>::ToDigit(LITERAL(T, 'F')));
|
always_check(0xF == TChar<T>::ToDigit(LITERAL(T, 'F'), 16));
|
||||||
|
|
||||||
always_check(LITERAL(T, '0') == TChar<T>::FromDigit(0x0));
|
always_check(LITERAL(T, '0') == TChar<T>::FromDigit(0x0, 16));
|
||||||
always_check(LITERAL(T, 'f') != TChar<T>::FromDigit(0xF));
|
always_check(LITERAL(T, 'f') != TChar<T>::FromDigit(0xF, 16));
|
||||||
always_check(LITERAL(T, 'F') == TChar<T>::FromDigit(0xF));
|
always_check(LITERAL(T, 'F') == TChar<T>::FromDigit(0xF, 16));
|
||||||
};
|
};
|
||||||
|
|
||||||
Test(InPlaceType<char>);
|
Test(InPlaceType<char>);
|
||||||
@ -536,6 +536,70 @@ void TestStringConversion()
|
|||||||
CheckParseFloat(InPlaceType<float>);
|
CheckParseFloat(InPlaceType<float>);
|
||||||
CheckParseFloat(InPlaceType<double>);
|
CheckParseFloat(InPlaceType<double>);
|
||||||
CheckParseFloat(InPlaceType<long double>);
|
CheckParseFloat(InPlaceType<long double>);
|
||||||
|
|
||||||
|
{
|
||||||
|
always_check(TString<T>::FromBool(true ) == LITERAL(T, "True" ));
|
||||||
|
always_check(TString<T>::FromBool(false) == LITERAL(T, "False"));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
always_check(TString<T>::FromInt(42) == LITERAL(T, "42" ));
|
||||||
|
always_check(TString<T>::FromInt(255, 16) == LITERAL(T, "FF" ));
|
||||||
|
always_check(TString<T>::FromInt(-42) == LITERAL(T, "-42" ));
|
||||||
|
always_check(TString<T>::FromInt(0) == LITERAL(T, "0" ));
|
||||||
|
always_check(TString<T>::FromInt(1234567890) == LITERAL(T, "1234567890"));
|
||||||
|
always_check(TString<T>::FromInt(255, 2) == LITERAL(T, "11111111" ));
|
||||||
|
always_check(TString<T>::FromInt(255, 8) == LITERAL(T, "377" ));
|
||||||
|
always_check(TString<T>::FromInt(255, 36) == LITERAL(T, "73" ));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
always_check(TString<T>::FromFloat(3.14f) == LITERAL(T, "3.14" ));
|
||||||
|
always_check(TString<T>::FromFloat(0.0f) == LITERAL(T, "0" ));
|
||||||
|
always_check(TString<T>::FromFloat(-3.14f) == LITERAL(T, "-3.14" ));
|
||||||
|
always_check(TString<T>::FromFloat(3.14f, true, false) == LITERAL(T, "3.14" ));
|
||||||
|
always_check(TString<T>::FromFloat(3.14f, false, true) == LITERAL(T, "3.14e+00"));
|
||||||
|
always_check(TString<T>::FromFloat(3.14f, false, false, 2) == LITERAL(T, "1.92p+1" ));
|
||||||
|
always_check(TString<T>::FromFloat(1.0f / 3.0f, true, false, 5) == LITERAL(T, "0.33333" ));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
always_check( LITERAL_VIEW(T, "True" ).ToBool());
|
||||||
|
always_check(!LITERAL_VIEW(T, "False" ).ToBool());
|
||||||
|
always_check( LITERAL_VIEW(T, "1" ).ToBool());
|
||||||
|
always_check(!LITERAL_VIEW(T, "0" ).ToBool());
|
||||||
|
always_check(!LITERAL_VIEW(T, "random").ToBool());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
always_check(LITERAL_VIEW(T, "42" ).ToInt() == 42 );
|
||||||
|
always_check(LITERAL_VIEW(T, "FF" ).ToInt(16) == 255);
|
||||||
|
always_check(LITERAL_VIEW(T, "-42" ).ToInt() == -42);
|
||||||
|
always_check(LITERAL_VIEW(T, "0" ).ToInt() == 0 );
|
||||||
|
always_check(LITERAL_VIEW(T, "Invalid").ToInt() == 0 );
|
||||||
|
|
||||||
|
always_check(LITERAL_VIEW(T, "999999999999999999999999999999").ToInt() == NAMESPACE_STD::numeric_limits<int>::max());
|
||||||
|
always_check(LITERAL_VIEW(T, "-999999999999999999999999999999").ToInt() == NAMESPACE_STD::numeric_limits<int>::min());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
always_check(LITERAL_VIEW(T, "3.14" ).ToFloat() == 3.14f );
|
||||||
|
always_check(LITERAL_VIEW(T, "3.14e+00").ToFloat() == 3.14f );
|
||||||
|
always_check(LITERAL_VIEW(T, "-3.14" ).ToFloat() == -3.14f);
|
||||||
|
always_check(LITERAL_VIEW(T, "0.0" ).ToFloat() == 0.0f );
|
||||||
|
|
||||||
|
always_check(LITERAL_VIEW(T, "1e+308").ToFloat() == NAMESPACE_STD::numeric_limits<float>::infinity());
|
||||||
|
always_check(LITERAL_VIEW(T, "-1e+308").ToFloat() == -NAMESPACE_STD::numeric_limits<float>::infinity());
|
||||||
|
always_check(LITERAL_VIEW(T, "1e-308").ToFloat() == 0.0f);
|
||||||
|
always_check(LITERAL_VIEW(T, "-1e-308").ToFloat() == -0.0f);
|
||||||
|
|
||||||
|
always_check(LITERAL_VIEW(T, "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.e-4").ToFloat() == NAMESPACE_STD::numeric_limits<float>::infinity());
|
||||||
|
always_check(LITERAL_VIEW(T, "-100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.e-4").ToFloat() == -NAMESPACE_STD::numeric_limits<float>::infinity());
|
||||||
|
always_check(LITERAL_VIEW(T, "1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-4").ToFloat() == NAMESPACE_STD::numeric_limits<float>::infinity());
|
||||||
|
always_check(LITERAL_VIEW(T, "-1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-4").ToFloat() == -NAMESPACE_STD::numeric_limits<float>::infinity());
|
||||||
|
always_check(LITERAL_VIEW(T, "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e+4").ToFloat() == 0.0f);
|
||||||
|
always_check(LITERAL_VIEW(T, "-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e+4").ToFloat() == -0.0f);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Test(InPlaceType<char>);
|
Test(InPlaceType<char>);
|
||||||
|
@ -161,7 +161,7 @@ struct TChar
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NODISCARD FORCEINLINE static constexpr bool IsASCII(CharType InChar)
|
NODISCARD FORCEINLINE static constexpr bool IsASCII(CharType InChar = LITERAL(CharType, '\0'))
|
||||||
{
|
{
|
||||||
if constexpr (CSameAs<CharType, char>)
|
if constexpr (CSameAs<CharType, char>)
|
||||||
{
|
{
|
||||||
@ -359,19 +359,30 @@ struct TChar
|
|||||||
|
|
||||||
NODISCARD FORCEINLINE static constexpr bool IsDigit(CharType InChar)
|
NODISCARD FORCEINLINE static constexpr bool IsDigit(CharType InChar)
|
||||||
{
|
{
|
||||||
|
static_assert(TChar::IsASCII());
|
||||||
|
|
||||||
/* <U0030>..<U0039>; */
|
/* <U0030>..<U0039>; */
|
||||||
return (InChar >= LITERAL(CharType, '0') && InChar <= LITERAL(CharType, '9'));
|
return InChar >= LITERAL(CharType, '0') && InChar <= LITERAL(CharType, '9');
|
||||||
}
|
}
|
||||||
|
|
||||||
NODISCARD FORCEINLINE static constexpr bool IsDigit(CharType InChar, unsigned Base)
|
NODISCARD FORCEINLINE static constexpr bool IsDigit(CharType InChar, unsigned Base)
|
||||||
{
|
{
|
||||||
checkf(Base >= 2 && Base <= 36, TEXT("Base must be in the range [2, 36]."));
|
checkf(Base >= 2 && Base <= 36, TEXT("Base must be in the range [2, 36]."));
|
||||||
|
|
||||||
/* <U0030>..<U0039>;<U0041>..<U0046>;<U0061>..<U0066>; */
|
static_assert(TChar::IsASCII());
|
||||||
return
|
|
||||||
(InChar >= LITERAL(CharType, '0') && InChar < LITERAL(CharType, '0') + static_cast<signed>(Base) ) ||
|
bool bResult = false;
|
||||||
(InChar >= LITERAL(CharType, 'a') && InChar < LITERAL(CharType, 'a') + static_cast<signed>(Base) - 10) ||
|
|
||||||
(InChar >= LITERAL(CharType, 'A') && InChar < LITERAL(CharType, 'A') + static_cast<signed>(Base) - 10);
|
/* <U0030>..<U0039>; */
|
||||||
|
bResult |= InChar >= LITERAL(CharType, '0') && InChar < LITERAL(CharType, '0') + static_cast<signed>(Base);
|
||||||
|
|
||||||
|
/* <U0041>..<U0046>; */
|
||||||
|
bResult |= InChar >= LITERAL(CharType, 'a') && InChar < LITERAL(CharType, 'a') + static_cast<signed>(Base) - 10;
|
||||||
|
|
||||||
|
/* <U0061>..<U0066>; */
|
||||||
|
bResult |= InChar >= LITERAL(CharType, 'A') && InChar < LITERAL(CharType, 'A') + static_cast<signed>(Base) - 10;
|
||||||
|
|
||||||
|
return bResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
NODISCARD FORCEINLINE static constexpr bool IsCntrl(CharType InChar)
|
NODISCARD FORCEINLINE static constexpr bool IsCntrl(CharType InChar)
|
||||||
@ -798,79 +809,42 @@ struct TChar
|
|||||||
return InChar;
|
return InChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
NODISCARD FORCEINLINE static constexpr TOptional<unsigned> ToDigit(CharType InChar)
|
NODISCARD FORCEINLINE static constexpr TOptional<unsigned> ToDigit(CharType InChar, unsigned Base = 10)
|
||||||
{
|
{
|
||||||
switch (InChar)
|
static_assert(TChar::IsASCII());
|
||||||
|
|
||||||
|
constexpr uint8 DigitFromChar[] =
|
||||||
{
|
{
|
||||||
case LITERAL(CharType, '0'): return 0;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, '1'): return 1;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, '2'): return 2;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, '3'): return 3;
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, '4'): return 4;
|
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||||
case LITERAL(CharType, '5'): return 5;
|
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, '6'): return 6;
|
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||||
case LITERAL(CharType, '7'): return 7;
|
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, '8'): return 8;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, '9'): return 9;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, 'a'): return 10;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, 'b'): return 11;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, 'c'): return 12;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, 'd'): return 13;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, 'e'): return 14;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, 'f'): return 15;
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
case LITERAL(CharType, 'g'): return 16;
|
};
|
||||||
case LITERAL(CharType, 'h'): return 17;
|
|
||||||
case LITERAL(CharType, 'i'): return 18;
|
static_assert(sizeof(DigitFromChar) == 256);
|
||||||
case LITERAL(CharType, 'j'): return 19;
|
|
||||||
case LITERAL(CharType, 'k'): return 20;
|
if constexpr (sizeof(CharType) > 1) if (InChar >> 8) return Invalid;
|
||||||
case LITERAL(CharType, 'l'): return 21;
|
|
||||||
case LITERAL(CharType, 'm'): return 22;
|
if (DigitFromChar[InChar] >= Base) return Invalid;
|
||||||
case LITERAL(CharType, 'n'): return 23;
|
|
||||||
case LITERAL(CharType, 'o'): return 24;
|
return DigitFromChar[InChar];
|
||||||
case LITERAL(CharType, 'p'): return 25;
|
|
||||||
case LITERAL(CharType, 'q'): return 26;
|
|
||||||
case LITERAL(CharType, 'r'): return 27;
|
|
||||||
case LITERAL(CharType, 's'): return 28;
|
|
||||||
case LITERAL(CharType, 't'): return 29;
|
|
||||||
case LITERAL(CharType, 'u'): return 30;
|
|
||||||
case LITERAL(CharType, 'v'): return 31;
|
|
||||||
case LITERAL(CharType, 'w'): return 32;
|
|
||||||
case LITERAL(CharType, 'x'): return 33;
|
|
||||||
case LITERAL(CharType, 'y'): return 34;
|
|
||||||
case LITERAL(CharType, 'z'): return 35;
|
|
||||||
case LITERAL(CharType, 'A'): return 10;
|
|
||||||
case LITERAL(CharType, 'B'): return 11;
|
|
||||||
case LITERAL(CharType, 'C'): return 12;
|
|
||||||
case LITERAL(CharType, 'D'): return 13;
|
|
||||||
case LITERAL(CharType, 'E'): return 14;
|
|
||||||
case LITERAL(CharType, 'F'): return 15;
|
|
||||||
case LITERAL(CharType, 'G'): return 16;
|
|
||||||
case LITERAL(CharType, 'H'): return 17;
|
|
||||||
case LITERAL(CharType, 'I'): return 18;
|
|
||||||
case LITERAL(CharType, 'J'): return 19;
|
|
||||||
case LITERAL(CharType, 'K'): return 20;
|
|
||||||
case LITERAL(CharType, 'L'): return 21;
|
|
||||||
case LITERAL(CharType, 'M'): return 22;
|
|
||||||
case LITERAL(CharType, 'N'): return 23;
|
|
||||||
case LITERAL(CharType, 'O'): return 24;
|
|
||||||
case LITERAL(CharType, 'P'): return 25;
|
|
||||||
case LITERAL(CharType, 'Q'): return 26;
|
|
||||||
case LITERAL(CharType, 'R'): return 27;
|
|
||||||
case LITERAL(CharType, 'S'): return 28;
|
|
||||||
case LITERAL(CharType, 'T'): return 29;
|
|
||||||
case LITERAL(CharType, 'U'): return 30;
|
|
||||||
case LITERAL(CharType, 'V'): return 31;
|
|
||||||
case LITERAL(CharType, 'W'): return 32;
|
|
||||||
case LITERAL(CharType, 'X'): return 33;
|
|
||||||
case LITERAL(CharType, 'Y'): return 34;
|
|
||||||
case LITERAL(CharType, 'Z'): return 35;
|
|
||||||
default: return Invalid;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NODISCARD FORCEINLINE static constexpr TOptional<CharType> FromDigit(int InDigit)
|
NODISCARD FORCEINLINE static constexpr TOptional<CharType> FromDigit(unsigned InDigit, unsigned Base = 10)
|
||||||
{
|
{
|
||||||
if (InDigit < 0 || InDigit > 35) return Invalid;
|
if (InDigit > Base) return Invalid;
|
||||||
|
|
||||||
return LITERAL(CharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit];
|
return LITERAL(CharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit];
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,10 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <charconv>
|
||||||
|
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4146)
|
#pragma warning(disable : 4146 4244)
|
||||||
|
|
||||||
NAMESPACE_REDCRAFT_BEGIN
|
NAMESPACE_REDCRAFT_BEGIN
|
||||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||||
@ -33,7 +34,7 @@ NAMESPACE_PRIVATE_BEGIN
|
|||||||
template <CCharType T, bool bIsFormat>
|
template <CCharType T, bool bIsFormat>
|
||||||
struct TStringHelper
|
struct TStringHelper
|
||||||
{
|
{
|
||||||
FORCEINLINE static bool FormatObject(auto& Result, TStringView<T> Fmt, auto& Object) requires (bIsFormat)
|
static FORCEINLINE bool FormatObject(auto& Result, TStringView<T> Fmt, auto& Object) requires (bIsFormat)
|
||||||
{
|
{
|
||||||
using U = TRemoveCVRef<decltype(Object)>;
|
using U = TRemoveCVRef<decltype(Object)>;
|
||||||
|
|
||||||
@ -119,7 +120,7 @@ struct TStringHelper
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCEINLINE static bool ParseObject(TStringView<T>& View, TStringView<T> Fmt, auto& Object) requires (!bIsFormat)
|
static FORCEINLINE bool ParseObject(TStringView<T>& View, TStringView<T> Fmt, auto& Object) requires (!bIsFormat)
|
||||||
{
|
{
|
||||||
using U = TRemoveCVRef<decltype(Object)>;
|
using U = TRemoveCVRef<decltype(Object)>;
|
||||||
|
|
||||||
@ -209,9 +210,13 @@ struct TStringHelper
|
|||||||
{
|
{
|
||||||
NumberType Result = Init;
|
NumberType Result = Init;
|
||||||
|
|
||||||
while (!View.IsEmpty() && (Base == 10 ? TChar<T>::IsDigit(View.Front()) : TChar<T>::IsDigit(View.Front(), Base)))
|
while (!View.IsEmpty())
|
||||||
{
|
{
|
||||||
Result = static_cast<NumberType>(Result * Base + *TChar<T>::ToDigit(View.Front()));
|
auto Digit = TChar<T>::ToDigit(View.Front(), Base);
|
||||||
|
|
||||||
|
if (!Digit) break;
|
||||||
|
|
||||||
|
Result = Result * static_cast<NumberType>(Base) + static_cast<NumberType>(*Digit);
|
||||||
|
|
||||||
View.RemovePrefix(1);
|
View.RemovePrefix(1);
|
||||||
}
|
}
|
||||||
@ -324,7 +329,7 @@ struct TStringHelper
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCEINLINE static size_t Do(auto& Result, TStringView<T> Fmt, auto ArgsTuple)
|
static FORCEINLINE size_t Do(auto& Result, TStringView<T> Fmt, auto ArgsTuple)
|
||||||
{
|
{
|
||||||
size_t FormattedObjectNum = 0;
|
size_t FormattedObjectNum = 0;
|
||||||
|
|
||||||
@ -574,6 +579,355 @@ size_t TStringView<T>::Parse(TStringView Fmt, Ts&... Args) const
|
|||||||
#undef ESCAPE_LEFT_BRACE
|
#undef ESCAPE_LEFT_BRACE
|
||||||
#undef ESCAPE_RIGHT_BRACE
|
#undef ESCAPE_RIGHT_BRACE
|
||||||
|
|
||||||
|
template <CCharType T>
|
||||||
|
constexpr bool TStringView<T>::ToBool() const
|
||||||
|
{
|
||||||
|
if (StartsWith(LITERAL(T, '1'))
|
||||||
|
|| StartsWith(LITERAL(T, "true"))
|
||||||
|
|| StartsWith(LITERAL(T, "True"))
|
||||||
|
|| StartsWith(LITERAL(T, "TRUE")))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StartsWith(LITERAL(T, '0'))
|
||||||
|
|| StartsWith(LITERAL(T, "false"))
|
||||||
|
|| StartsWith(LITERAL(T, "False"))
|
||||||
|
|| StartsWith(LITERAL(T, "FALSE")))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToInt() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <CCharType T>
|
||||||
|
template <CIntegral U> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||||
|
constexpr U TStringView<T>::ToInt(unsigned Base) const
|
||||||
|
{
|
||||||
|
checkf(Base >= 2 && Base <= 36, TEXT("Illegal base. Please check the base."));
|
||||||
|
|
||||||
|
bool bNegative = false;
|
||||||
|
|
||||||
|
TStringView View = *this;
|
||||||
|
|
||||||
|
if constexpr (CSigned<U>)
|
||||||
|
{
|
||||||
|
if (View.StartsWith(LITERAL(ElementType, '-')))
|
||||||
|
{
|
||||||
|
bNegative = true;
|
||||||
|
View.RemovePrefix(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using UnsignedU = TMakeUnsigned<U>;
|
||||||
|
|
||||||
|
constexpr UnsignedU UnsignedMaximum = static_cast<UnsignedU>(-1);
|
||||||
|
|
||||||
|
constexpr U SignedMaximum = static_cast<U>(UnsignedMaximum >> 1);
|
||||||
|
constexpr U SignedMinimum = -static_cast<U>(SignedMaximum) - 1;
|
||||||
|
|
||||||
|
UnsignedU LastValue = 0;
|
||||||
|
UnsignedU Value = 0;
|
||||||
|
|
||||||
|
for (ElementType Char : View)
|
||||||
|
{
|
||||||
|
auto Digit = TChar<ElementType>::ToDigit(Char, Base);
|
||||||
|
|
||||||
|
if (!Digit) break;
|
||||||
|
|
||||||
|
LastValue = Value;
|
||||||
|
|
||||||
|
Value = static_cast<UnsignedU>(LastValue * Base + *Digit);
|
||||||
|
|
||||||
|
if (Value < LastValue)
|
||||||
|
{
|
||||||
|
if constexpr (CSigned<U>)
|
||||||
|
{
|
||||||
|
return bNegative ? SignedMinimum : SignedMaximum;
|
||||||
|
}
|
||||||
|
else return UnsignedMaximum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (CSigned<U>)
|
||||||
|
{
|
||||||
|
if (!bNegative && Value >= static_cast<UnsignedU>(SignedMaximum)) return SignedMaximum;
|
||||||
|
if ( bNegative && Value >= static_cast<UnsignedU>(SignedMinimum)) return SignedMinimum;
|
||||||
|
|
||||||
|
if (bNegative) Value = static_cast<UnsignedU>(-Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<U>(Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <CCharType T>
|
||||||
|
template <CFloatingPoint U> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
constexpr U TStringView<T>::ToFloat(bool bFixed, bool bScientific) const
|
||||||
|
{
|
||||||
|
NAMESPACE_STD::chars_format Format;
|
||||||
|
|
||||||
|
if ( bFixed && bScientific) Format = NAMESPACE_STD::chars_format::general;
|
||||||
|
else if ( bFixed && !bScientific) Format = NAMESPACE_STD::chars_format::fixed;
|
||||||
|
else if (!bFixed && bScientific) Format = NAMESPACE_STD::chars_format::scientific;
|
||||||
|
else Format = NAMESPACE_STD::chars_format::hex;
|
||||||
|
|
||||||
|
U Result;
|
||||||
|
|
||||||
|
auto Iter = this->Begin();
|
||||||
|
|
||||||
|
bool bNegativeMantissa = false;
|
||||||
|
bool bNegativeExponent = false;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (Iter == this->End()) break;
|
||||||
|
|
||||||
|
if (*Iter == LITERAL(ElementType, '-'))
|
||||||
|
{
|
||||||
|
bNegativeMantissa = true;
|
||||||
|
++Iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto DecimalPoint = this->End();
|
||||||
|
auto NonZeroBegin = this->End();
|
||||||
|
|
||||||
|
while (Iter != this->End())
|
||||||
|
{
|
||||||
|
if (DecimalPoint == this->End() && *Iter == LITERAL(ElementType, '.'))
|
||||||
|
{
|
||||||
|
DecimalPoint = Iter;
|
||||||
|
}
|
||||||
|
else if (TChar<ElementType>::IsDigit(*Iter, Format == NAMESPACE_STD::chars_format::hex ? 16 : 10))
|
||||||
|
{
|
||||||
|
if (NonZeroBegin == this->End() && *Iter != LITERAL(ElementType, '0'))
|
||||||
|
{
|
||||||
|
NonZeroBegin = Iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
|
||||||
|
++Iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DecimalPoint == this->End()) DecimalPoint = Iter;
|
||||||
|
|
||||||
|
bNegativeExponent = DecimalPoint < NonZeroBegin;
|
||||||
|
|
||||||
|
if (Iter == this->End()) break;
|
||||||
|
|
||||||
|
bool bHasExponent = false;
|
||||||
|
|
||||||
|
if (Format == NAMESPACE_STD::chars_format::general || Format == NAMESPACE_STD::chars_format::scientific)
|
||||||
|
{
|
||||||
|
if (*Iter == LITERAL(ElementType, 'e') || *Iter == LITERAL(ElementType, 'E'))
|
||||||
|
{
|
||||||
|
bHasExponent = true;
|
||||||
|
++Iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Format == NAMESPACE_STD::chars_format::hex)
|
||||||
|
{
|
||||||
|
if (*Iter == LITERAL(ElementType, 'p') || *Iter == LITERAL(ElementType, 'P'))
|
||||||
|
{
|
||||||
|
bHasExponent = true;
|
||||||
|
++Iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Iter == this->End() || !bHasExponent) break;
|
||||||
|
|
||||||
|
if (*Iter == LITERAL(ElementType, '+')) ++Iter;
|
||||||
|
if (*Iter == LITERAL(ElementType, '-')) { bNegativeExponent = true; ++Iter; }
|
||||||
|
|
||||||
|
auto ExponentBegin = Iter;
|
||||||
|
|
||||||
|
while (Iter != this->End() && TChar<ElementType>::IsDigit(*Iter, 10)) ++Iter;
|
||||||
|
|
||||||
|
auto ExponentEnd = Iter;
|
||||||
|
|
||||||
|
if (NonZeroBegin == this->End()) break;
|
||||||
|
|
||||||
|
auto Exponent = TStringView(ExponentBegin, ExponentEnd).ToInt();
|
||||||
|
|
||||||
|
if (bNegativeExponent) Exponent = -Exponent;
|
||||||
|
|
||||||
|
Exponent += static_cast<int>(DecimalPoint - NonZeroBegin);
|
||||||
|
|
||||||
|
bNegativeExponent = Exponent < 0;
|
||||||
|
}
|
||||||
|
while (false);
|
||||||
|
|
||||||
|
NAMESPACE_STD::from_chars_result ConvertResult;
|
||||||
|
|
||||||
|
if constexpr (!CSameAs<ElementType, char>)
|
||||||
|
{
|
||||||
|
TArray<char, TInlineAllocator<64>> Buffer(this->Begin(), Iter);
|
||||||
|
|
||||||
|
ConvertResult = NAMESPACE_STD::from_chars(ToAddress(Buffer.Begin()), ToAddress(Buffer.End()), Result, Format);
|
||||||
|
}
|
||||||
|
else ConvertResult = NAMESPACE_STD::from_chars(ToAddress(this->Begin()), ToAddress(this->End()), Result, Format);
|
||||||
|
|
||||||
|
if (ConvertResult.ec == NAMESPACE_STD::errc::result_out_of_range)
|
||||||
|
{
|
||||||
|
if (!bNegativeMantissa && !bNegativeExponent) return NAMESPACE_STD::numeric_limits<U>::infinity();
|
||||||
|
if ( bNegativeMantissa && !bNegativeExponent) return -NAMESPACE_STD::numeric_limits<U>::infinity();
|
||||||
|
if (!bNegativeMantissa && bNegativeExponent) return static_cast<U>( 0.0);
|
||||||
|
return static_cast<U>(-0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ConvertResult.ec == NAMESPACE_STD::errc::invalid_argument) return NAMESPACE_STD::numeric_limits<U>::quiet_NaN();
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <CCharType T, CAllocator<T> Allocator>
|
||||||
|
void TString<T, Allocator>::AppendBool(bool Value)
|
||||||
|
{
|
||||||
|
if (Value) Append(LITERAL(ElementType, "True"));
|
||||||
|
else Append(LITERAL(ElementType, "False"));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <CCharType T, CAllocator<T> Allocator>
|
||||||
|
template <CIntegral U> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||||
|
void TString<T, Allocator>::AppendInt(U Value, unsigned Base)
|
||||||
|
{
|
||||||
|
checkf(Base >= 2 && Base <= 36, TEXT("Illegal base. Please check the base."));
|
||||||
|
|
||||||
|
constexpr const ElementType* DigitToChar = LITERAL(ElementType, "0123456789ABCDEF");
|
||||||
|
|
||||||
|
using UnsignedU = TMakeUnsigned<U>;
|
||||||
|
|
||||||
|
UnsignedU Unsigned = static_cast<UnsignedU>(Value);
|
||||||
|
|
||||||
|
bool bNegative = false;
|
||||||
|
|
||||||
|
if constexpr (CSigned<U>)
|
||||||
|
{
|
||||||
|
if (Value < 0)
|
||||||
|
{
|
||||||
|
bNegative = true;
|
||||||
|
|
||||||
|
Unsigned = static_cast<UnsignedU>(-Unsigned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t BufferSize = sizeof(UnsignedU) * 8 + (CSigned<U> ? 1 : 0);
|
||||||
|
|
||||||
|
ElementType Buffer[BufferSize];
|
||||||
|
|
||||||
|
ElementType* Iter = Buffer + BufferSize;
|
||||||
|
|
||||||
|
switch (Base)
|
||||||
|
{
|
||||||
|
case 0x02: do { *--Iter = static_cast<ElementType>('0' + (Unsigned & 0b00001)); Unsigned >>= 1; } while (Unsigned != 0); break;
|
||||||
|
case 0x04: do { *--Iter = static_cast<ElementType>('0' + (Unsigned & 0b00011)); Unsigned >>= 2; } while (Unsigned != 0); break;
|
||||||
|
case 0x08: do { *--Iter = static_cast<ElementType>('0' + (Unsigned & 0b00111)); Unsigned >>= 3; } while (Unsigned != 0); break;
|
||||||
|
case 0x10: do { *--Iter = DigitToChar[Unsigned & 0b01111]; Unsigned >>= 4; } while (Unsigned != 0); break;
|
||||||
|
case 0X20: do { *--Iter = DigitToChar[Unsigned & 0b11111]; Unsigned >>= 5; } while (Unsigned != 0); break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 9:
|
||||||
|
case 10: do { *--Iter = static_cast<ElementType>('0' + Unsigned % Base); Unsigned = static_cast<UnsignedU>(Unsigned / Base); } while (Unsigned != 0); break;
|
||||||
|
default: do { *--Iter = DigitToChar[Unsigned % Base]; Unsigned = static_cast<UnsignedU>(Unsigned / Base); } while (Unsigned != 0); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (CSigned<U>) if (bNegative) *--Iter = LITERAL(T, '-');
|
||||||
|
|
||||||
|
Append(Iter, Buffer + BufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_PRIVATE_BEGIN
|
||||||
|
|
||||||
|
template <CCharType T, size_t Overload>
|
||||||
|
struct TStringFloatSerializer
|
||||||
|
{
|
||||||
|
static FORCEINLINE void Do(auto& Result, auto Value, bool bFixed, bool bScientific, unsigned Precision)
|
||||||
|
{
|
||||||
|
NAMESPACE_STD::chars_format Format;
|
||||||
|
|
||||||
|
if constexpr (Overload >= 1)
|
||||||
|
{
|
||||||
|
if ( bFixed && bScientific) Format = NAMESPACE_STD::chars_format::general;
|
||||||
|
else if ( bFixed && !bScientific) Format = NAMESPACE_STD::chars_format::fixed;
|
||||||
|
else if (!bFixed && bScientific) Format = NAMESPACE_STD::chars_format::scientific;
|
||||||
|
else Format = NAMESPACE_STD::chars_format::hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t StartingBufferSize = 64;
|
||||||
|
|
||||||
|
TArray<char, TInlineAllocator<StartingBufferSize>> Buffer(StartingBufferSize / 2);
|
||||||
|
|
||||||
|
NAMESPACE_STD::to_chars_result ConvertResult;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Buffer.SetNum(Buffer.Num() * 2);
|
||||||
|
|
||||||
|
if constexpr (Overload == 0) ConvertResult = NAMESPACE_STD::to_chars(ToAddress(Buffer.Begin()), ToAddress(Buffer.End()), Value);
|
||||||
|
else if constexpr (Overload == 1) ConvertResult = NAMESPACE_STD::to_chars(ToAddress(Buffer.Begin()), ToAddress(Buffer.End()), Value, Format);
|
||||||
|
else ConvertResult = NAMESPACE_STD::to_chars(ToAddress(Buffer.Begin()), ToAddress(Buffer.End()), Value, Format, Precision);
|
||||||
|
}
|
||||||
|
while (ConvertResult.ec == NAMESPACE_STD::errc::value_too_large);
|
||||||
|
|
||||||
|
Buffer.SetNum(ConvertResult.ptr - Buffer.GetData());
|
||||||
|
|
||||||
|
const bool bNegative = Buffer[0] == '-';
|
||||||
|
|
||||||
|
const char* Iter = Buffer.GetData() + (bNegative ? 1 : 0);
|
||||||
|
|
||||||
|
if (*Iter == 'i')
|
||||||
|
{
|
||||||
|
if (bNegative) Result.Append(LITERAL(T, "-Infinity"));
|
||||||
|
else Result.Append(LITERAL(T, "Infinity"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*Iter == 'n')
|
||||||
|
{
|
||||||
|
if (bNegative) Result.Append(LITERAL(T, "-NaN"));
|
||||||
|
else Result.Append(LITERAL(T, "NaN"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Base;
|
||||||
|
|
||||||
|
if constexpr (Overload == 0) Base = 10;
|
||||||
|
else Base = Format == NAMESPACE_STD::chars_format::hex ? 16 : 10;
|
||||||
|
|
||||||
|
for (char& Char : Buffer)
|
||||||
|
{
|
||||||
|
const auto Digit = FChar::ToDigit(Char, Base);
|
||||||
|
if (Digit) Char = *FChar::FromDigit(*Digit, Base);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result.Append(Buffer.Begin(), Buffer.End());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_PRIVATE_END
|
||||||
|
|
||||||
|
template <CCharType T, CAllocator<T> Allocator> template <CFloatingPoint U> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
void TString<T, Allocator>::AppendFloat(U Value)
|
||||||
|
{
|
||||||
|
NAMESPACE_PRIVATE::TStringFloatSerializer<ElementType, 0>::Do(*this, Value, false, false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <CCharType T, CAllocator<T> Allocator> template <CFloatingPoint U> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
void TString<T, Allocator>::AppendFloat(U Value, bool bFixed, bool bScientific)
|
||||||
|
{
|
||||||
|
NAMESPACE_PRIVATE::TStringFloatSerializer<ElementType, 1>::Do(*this, Value, bFixed, bScientific, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <CCharType T, CAllocator<T> Allocator> template <CFloatingPoint U> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
void TString<T, Allocator>::AppendFloat(U Value, bool bFixed, bool bScientific, unsigned Precision)
|
||||||
|
{
|
||||||
|
NAMESPACE_PRIVATE::TStringFloatSerializer<ElementType, 2>::Do(*this, Value, bFixed, bScientific, Precision);
|
||||||
|
}
|
||||||
|
|
||||||
NAMESPACE_MODULE_END(Utility)
|
NAMESPACE_MODULE_END(Utility)
|
||||||
NAMESPACE_MODULE_END(Redcraft)
|
NAMESPACE_MODULE_END(Redcraft)
|
||||||
NAMESPACE_REDCRAFT_END
|
NAMESPACE_REDCRAFT_END
|
||||||
|
@ -1022,29 +1022,191 @@ public:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/** @return true if the string only contains valid characters, false otherwise. */
|
/** @return true if the string only contains valid characters, false otherwise. */
|
||||||
NODISCARD FORCEINLINE constexpr bool IsValid() const
|
NODISCARD FORCEINLINE bool IsValid() const
|
||||||
{
|
{
|
||||||
return TStringView<ElementType>(*this).IsValid();
|
return TStringView<ElementType>(*this).IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return true if the string only contains ASCII characters, false otherwise. */
|
/** @return true if the string only contains ASCII characters, false otherwise. */
|
||||||
NODISCARD FORCEINLINE constexpr bool IsASCII() const
|
NODISCARD FORCEINLINE bool IsASCII() const
|
||||||
{
|
{
|
||||||
return TStringView<ElementType>(*this).IsASCII();
|
return TStringView<ElementType>(*this).IsASCII();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return true if the string only contains numeric characters, false otherwise. */
|
/** @return true if the string only contains numeric characters, false otherwise. */
|
||||||
NODISCARD FORCEINLINE constexpr bool IsNumeric() const
|
NODISCARD FORCEINLINE bool IsNumeric(unsigned Base = 10) const
|
||||||
{
|
|
||||||
return TStringView<ElementType>(*this).IsNumeric();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return true if the string only contains numeric characters, false otherwise. */
|
|
||||||
NODISCARD FORCEINLINE constexpr bool IsNumeric(unsigned Base) const
|
|
||||||
{
|
{
|
||||||
return TStringView<ElementType>(*this).IsNumeric(Base);
|
return TStringView<ElementType>(*this).IsNumeric(Base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a boolean value into a string.
|
||||||
|
*
|
||||||
|
* - true becomes "True".
|
||||||
|
* - false becomes "False".
|
||||||
|
*
|
||||||
|
* @return The string containing the boolean value.
|
||||||
|
*/
|
||||||
|
NODISCARD static FORCEINLINE TString FromBool(bool Value)
|
||||||
|
{
|
||||||
|
TString Result;
|
||||||
|
|
||||||
|
Result.AppendBool(Value);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an integer value into a string.
|
||||||
|
*
|
||||||
|
* @param Base - The base of the number, between [2, 36].
|
||||||
|
*
|
||||||
|
* @return The string containing the integer value.
|
||||||
|
*/
|
||||||
|
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD static FORCEINLINE TString FromInt(U Value, unsigned Base = 10)
|
||||||
|
{
|
||||||
|
checkf(Base >= 2 && Base <= 36, TEXT("Illegal base. Please check the base."));
|
||||||
|
|
||||||
|
TString Result;
|
||||||
|
|
||||||
|
Result.AppendInt(Value, Base);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a floating-point value into a string.
|
||||||
|
* The string is formatted using the shortest representation in fixed-point or scientific notation.
|
||||||
|
*
|
||||||
|
* @return The string containing the floating-point value.
|
||||||
|
*/
|
||||||
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD static FORCEINLINE TString FromFloat(U Value)
|
||||||
|
{
|
||||||
|
TString Result;
|
||||||
|
|
||||||
|
Result.AppendFloat(Value);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a floating-point value into a string.
|
||||||
|
* The string is formatted using the shortest representation in fixed-point or scientific notation.
|
||||||
|
* The string is formatted using the hex representation if bFixed and bScientific are false.
|
||||||
|
*
|
||||||
|
* @param bFixed - The fixed-point format.
|
||||||
|
* @param bScientific - The scientific notation.
|
||||||
|
*
|
||||||
|
* @return The string containing the floating-point value.
|
||||||
|
*/
|
||||||
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD static FORCEINLINE TString FromFloat(U Value, bool bFixed, bool bScientific)
|
||||||
|
{
|
||||||
|
TString Result;
|
||||||
|
|
||||||
|
Result.AppendFloat(Value, bFixed, bScientific);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a floating-point value into a string.
|
||||||
|
* The string is formatted using the shortest representation in fixed-point or scientific notation.
|
||||||
|
* The string is formatted using the hex representation if bFixed and bScientific are false.
|
||||||
|
*
|
||||||
|
* @param bFixed - The fixed-point format.
|
||||||
|
* @param bScientific - The scientific notation.
|
||||||
|
* @param Precision - The number of digits after the decimal point.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD static FORCEINLINE TString FromFloat(U Value, bool bFixed, bool bScientific, unsigned Precision)
|
||||||
|
{
|
||||||
|
TString Result;
|
||||||
|
|
||||||
|
Result.AppendFloat(Value, bFixed, bScientific, Precision);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Converts a boolean value into a string and appends it to the string. */
|
||||||
|
void AppendBool(bool Value);
|
||||||
|
|
||||||
|
/** Converts an integer value into a string and appends it to the string. */
|
||||||
|
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||||
|
void AppendInt(U Value, unsigned Base = 10);
|
||||||
|
|
||||||
|
/** Converts a floating-point value into a string and appends it to the string. */
|
||||||
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
void AppendFloat(U Value);
|
||||||
|
|
||||||
|
/** Converts a floating-point value into a string and appends it to the string. */
|
||||||
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
void AppendFloat(U Value, bool bFixed, bool bScientific);
|
||||||
|
|
||||||
|
/** Converts a floating-point value into a string and appends it to the string. */
|
||||||
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
void AppendFloat(U Value, bool bFixed, bool bScientific, unsigned Precision);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string into a boolean value.
|
||||||
|
*
|
||||||
|
* - 1, "true", "True", "TRUE" and non-zero integers become true.
|
||||||
|
* - 0, "false", "False", "FALSE" and unparsable values become false.
|
||||||
|
*
|
||||||
|
* @return The boolean value.
|
||||||
|
*/
|
||||||
|
NODISCARD FORCEINLINE bool ToBool() const
|
||||||
|
{
|
||||||
|
return TStringView<ElementType>(*this).ToBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string into an integer value.
|
||||||
|
*
|
||||||
|
* - "0x" or "0X" prefixes are not recognized if base is 16.
|
||||||
|
* - Only the minus sign is recognized (not the plus sign), and only for signed integer types of value.
|
||||||
|
* - Leading whitespace is not ignored.
|
||||||
|
*
|
||||||
|
* Ensure that the entire string can be parsed if IsNumeric(Base, false, true, false) is true.
|
||||||
|
*
|
||||||
|
* @param Base - The base of the number, between [2, 36].
|
||||||
|
*
|
||||||
|
* @return The integer value.
|
||||||
|
*/
|
||||||
|
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD FORCEINLINE U ToInt(unsigned Base = 10) const
|
||||||
|
{
|
||||||
|
checkf(Base >= 2 && Base <= 36, TEXT("Illegal base. Please check the base."));
|
||||||
|
|
||||||
|
return TStringView<ElementType>(*this).template ToInt<U>(Base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string into a floating-point value.
|
||||||
|
*
|
||||||
|
* - "0x" or "0X" prefixes are not recognized if base is 16.
|
||||||
|
* - The plus sign is not recognized outside the exponent (only the minus sign is permitted at the beginning).
|
||||||
|
* - Leading whitespace is not ignored.
|
||||||
|
*
|
||||||
|
* Ensure that the entire string can be parsed if bFixed and IsNumeric(10, false) is true.
|
||||||
|
* Parsers hex floating-point values if bFixed and bScientific are false.
|
||||||
|
*
|
||||||
|
* @param bFixed - The fixed-point format.
|
||||||
|
* @param bScientific - The scientific notation.
|
||||||
|
*
|
||||||
|
* @return The floating-point value.
|
||||||
|
*/
|
||||||
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD FORCEINLINE U ToFloat(bool bFixed = true, bool bScientific = false) const
|
||||||
|
{
|
||||||
|
return TStringView<ElementType>(*this).template ToFloat<U>(bFixed, bScientific);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1067,7 +1229,7 @@ public:
|
|||||||
* @return The number of objects successfully parsed.
|
* @return The number of objects successfully parsed.
|
||||||
*/
|
*/
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
size_t Parse(TStringView<ElementType> Fmt, Ts&... Args) const
|
FORCEINLINE size_t Parse(TStringView<ElementType> Fmt, Ts&... Args) const
|
||||||
{
|
{
|
||||||
return TStringView(*this).Parse(Fmt, Args...);
|
return TStringView(*this).Parse(Fmt, Args...);
|
||||||
}
|
}
|
||||||
|
@ -402,18 +402,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @return true if the string only contains numeric characters, false otherwise. */
|
/** @return true if the string only contains numeric characters, false otherwise. */
|
||||||
NODISCARD constexpr bool IsNumeric() const
|
NODISCARD constexpr bool IsNumeric(unsigned Base = 10) const
|
||||||
{
|
|
||||||
for (ElementType Char : *this)
|
|
||||||
{
|
|
||||||
if (!TChar<ElementType>::IsDigit(Char)) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return true if the string only contains numeric characters, false otherwise. */
|
|
||||||
NODISCARD constexpr bool IsNumeric(unsigned Base) const
|
|
||||||
{
|
{
|
||||||
for (ElementType Char : *this)
|
for (ElementType Char : *this)
|
||||||
{
|
{
|
||||||
@ -423,6 +412,52 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string into a boolean value.
|
||||||
|
*
|
||||||
|
* - 1, "true", "True", "TRUE" and non-zero integers become true.
|
||||||
|
* - 0, "false", "False", "FALSE" and unparsable values become false.
|
||||||
|
*
|
||||||
|
* @return The boolean value.
|
||||||
|
*/
|
||||||
|
NODISCARD constexpr bool ToBool() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string into an integer value.
|
||||||
|
*
|
||||||
|
* - "0x" or "0X" prefixes are not recognized if base is 16.
|
||||||
|
* - Only the minus sign is recognized (not the plus sign), and only for signed integer types of value.
|
||||||
|
* - Leading whitespace is not ignored.
|
||||||
|
*
|
||||||
|
* Ensure that the entire string can be parsed if IsNumeric(Base, false, true, false) is true.
|
||||||
|
*
|
||||||
|
* @param Base - The base of the number, between [2, 36].
|
||||||
|
*
|
||||||
|
* @return The integer value.
|
||||||
|
*/
|
||||||
|
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD constexpr U ToInt(unsigned Base = 10) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string into a floating-point value.
|
||||||
|
*
|
||||||
|
* - "0x" or "0X" prefixes are not recognized if base is 16.
|
||||||
|
* - The plus sign is not recognized outside the exponent (only the minus sign is permitted at the beginning).
|
||||||
|
* - Leading whitespace is not ignored.
|
||||||
|
*
|
||||||
|
* Ensure that the entire string can be parsed if bFixed and IsNumeric(10, false) is true.
|
||||||
|
* Parsers hex floating-point values if bFixed and bScientific are false.
|
||||||
|
*
|
||||||
|
* @param bFixed - The fixed-point format.
|
||||||
|
* @param bScientific - The scientific notation.
|
||||||
|
*
|
||||||
|
* @return The floating-point value.
|
||||||
|
*/
|
||||||
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD constexpr U ToFloat(bool bFixed = true, bool bScientific = true) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user