feat(string): add string and arithmetic conversion functions
This commit is contained in:
parent
49feb0b12b
commit
fe60fc33e0
@ -536,6 +536,70 @@ void TestStringConversion()
|
||||
CheckParseFloat(InPlaceType<float>);
|
||||
CheckParseFloat(InPlaceType<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>);
|
||||
|
@ -8,9 +8,10 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <charconv>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
#pragma warning(disable : 4146 4244)
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
@ -33,7 +34,7 @@ NAMESPACE_PRIVATE_BEGIN
|
||||
template <CCharType T, bool bIsFormat>
|
||||
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)>;
|
||||
|
||||
@ -119,7 +120,7 @@ struct TStringHelper
|
||||
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)>;
|
||||
|
||||
@ -328,7 +329,7 @@ struct TStringHelper
|
||||
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;
|
||||
|
||||
@ -578,6 +579,355 @@ size_t TStringView<T>::Parse(TStringView Fmt, Ts&... Args) const
|
||||
#undef ESCAPE_LEFT_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(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
||||
|
@ -1022,29 +1022,191 @@ public:
|
||||
public:
|
||||
|
||||
/** @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 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 true if the string only contains numeric characters, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr bool IsNumeric() 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
|
||||
NODISCARD FORCEINLINE bool IsNumeric(unsigned Base = 10) const
|
||||
{
|
||||
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:
|
||||
|
||||
/**
|
||||
@ -1067,7 +1229,7 @@ public:
|
||||
* @return The number of objects successfully parsed.
|
||||
*/
|
||||
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...);
|
||||
}
|
||||
|
@ -402,18 +402,7 @@ public:
|
||||
}
|
||||
|
||||
/** @return true if the string only contains numeric characters, false otherwise. */
|
||||
NODISCARD constexpr bool IsNumeric() 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
|
||||
NODISCARD constexpr bool IsNumeric(unsigned Base = 10) const
|
||||
{
|
||||
for (ElementType Char : *this)
|
||||
{
|
||||
@ -423,6 +412,52 @@ public:
|
||||
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:
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user