feat(string): add string trimming functions
This commit is contained in:
parent
bc93455d0e
commit
3859070d53
@ -175,13 +175,21 @@ void TestStringView()
|
|||||||
always_check(View.FindLastNotOf(LITERAL(T, '!')) == 27);
|
always_check(View.FindLastNotOf(LITERAL(T, '!')) == 27);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
always_check(LITERAL_VIEW(T, " ABC ").TrimStart() == LITERAL(T, "ABC "));
|
||||||
|
always_check(LITERAL_VIEW(T, " ABC ").TrimEnd() == LITERAL(T, " ABC" ));
|
||||||
|
always_check(LITERAL_VIEW(T, " ABC ").TrimStartAndEnd() == LITERAL(T, "ABC" ));
|
||||||
|
|
||||||
|
always_check(LITERAL_VIEW(T, " A\0C ").TrimToNullTerminator() == LITERAL(T, " A"));
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
always_check( LITERAL_VIEW(T, "012345678900").IsASCII());
|
always_check( LITERAL_VIEW(T, "012345678900").IsASCII());
|
||||||
always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").IsASCII());
|
always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").IsASCII());
|
||||||
always_check( LITERAL_VIEW(T, "012345678900").IsNumeric());
|
always_check( LITERAL_VIEW(T, "012345678900").IsInteger());
|
||||||
always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").IsNumeric());
|
always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").IsInteger());
|
||||||
always_check(!LITERAL_VIEW(T, "0123456789AB").IsNumeric());
|
always_check(!LITERAL_VIEW(T, "0123456789AB").IsInteger());
|
||||||
always_check( LITERAL_VIEW(T, "0123456789AB").IsNumeric(16));
|
always_check( LITERAL_VIEW(T, "0123456789AB").IsInteger(16));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -404,6 +412,14 @@ void TestTemplateString()
|
|||||||
always_check(Str.FindLastNotOf(LITERAL(T, '!')) == 27);
|
always_check(Str.FindLastNotOf(LITERAL(T, '!')) == 27);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
always_check(TString(LITERAL(T, " ABC ")).TrimStart() == LITERAL(T, "ABC "));
|
||||||
|
always_check(TString(LITERAL(T, " ABC ")).TrimEnd() == LITERAL(T, " ABC" ));
|
||||||
|
always_check(TString(LITERAL(T, " ABC ")).TrimStartAndEnd() == LITERAL(T, "ABC" ));
|
||||||
|
|
||||||
|
always_check(TString(LITERAL(T, " A\0C ")).TrimToNullTerminator() == LITERAL(T, " A"));
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
always_check(TString(LITERAL(T, "\u4E38\u8FA3")).ToString() == TEXT("\u4E38\u8FA3"));
|
always_check(TString(LITERAL(T, "\u4E38\u8FA3")).ToString() == TEXT("\u4E38\u8FA3"));
|
||||||
always_check(TString(LITERAL(T, "\u4E38\u8FA3")).ToWString() == WTEXT("\u4E38\u8FA3"));
|
always_check(TString(LITERAL(T, "\u4E38\u8FA3")).ToWString() == WTEXT("\u4E38\u8FA3"));
|
||||||
|
@ -457,7 +457,7 @@ struct TStringHelper
|
|||||||
|
|
||||||
if (IndexLength != 0)
|
if (IndexLength != 0)
|
||||||
{
|
{
|
||||||
if (!PlaceholderIndex.IsNumeric())
|
if (!PlaceholderIndex.IsInteger(10, false))
|
||||||
{
|
{
|
||||||
checkf(false, TEXT("Invalid placeholder index."));
|
checkf(false, TEXT("Invalid placeholder index."));
|
||||||
|
|
||||||
@ -550,27 +550,23 @@ NAMESPACE_PRIVATE_END
|
|||||||
|
|
||||||
template <CCharType T, CAllocator<T> Allocator>
|
template <CCharType T, CAllocator<T> Allocator>
|
||||||
template <typename ... Ts>
|
template <typename ... Ts>
|
||||||
TString<T, Allocator> TString<T, Allocator>::Format(TStringView<ElementType> Fmt, const Ts&... Args)
|
void TString<T, Allocator>::AppendFormat(TStringView<ElementType> Fmt, const Ts&... Args)
|
||||||
{
|
{
|
||||||
// The Unreal Engine says that the starting buffer size catches 99.97% of printf calls.
|
// The Unreal Engine says that the starting buffer size catches 99.97% of printf calls.
|
||||||
constexpr size_t ReserveBufferSize = 512;
|
constexpr size_t ReserveBufferSize = 512;
|
||||||
|
|
||||||
TString Result;
|
TString<T, TInlineAllocator<ReserveBufferSize>> Result;
|
||||||
|
|
||||||
Result.Reserve(ReserveBufferSize);
|
|
||||||
|
|
||||||
NAMESPACE_PRIVATE::TStringHelper<ElementType, true>::Do(Result, Fmt, ForwardAsTuple(Args...));
|
NAMESPACE_PRIVATE::TStringHelper<ElementType, true>::Do(Result, Fmt, ForwardAsTuple(Args...));
|
||||||
|
|
||||||
return Result;
|
Append(Result.Begin(), Result.End());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <CCharType T>
|
template <CCharType T>
|
||||||
template <typename ... Ts>
|
template <typename ... Ts>
|
||||||
size_t TStringView<T>::Parse(TStringView Fmt, Ts&... Args) const
|
size_t TStringView<T>::ParseAndTrim(TStringView Fmt, Ts&... Args)
|
||||||
{
|
{
|
||||||
TStringView View = *this;
|
return NAMESPACE_PRIVATE::TStringHelper<ElementType, false>::Do(*this, Fmt, ForwardAsTuple(Args...));
|
||||||
|
|
||||||
return NAMESPACE_PRIVATE::TStringHelper<ElementType, false>::Do(View, Fmt, ForwardAsTuple(Args...));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef LEFT_BRACE
|
#undef LEFT_BRACE
|
||||||
@ -580,43 +576,55 @@ size_t TStringView<T>::Parse(TStringView Fmt, Ts&... Args) const
|
|||||||
#undef ESCAPE_RIGHT_BRACE
|
#undef ESCAPE_RIGHT_BRACE
|
||||||
|
|
||||||
template <CCharType T>
|
template <CCharType T>
|
||||||
constexpr bool TStringView<T>::ToBool() const
|
constexpr bool TStringView<T>::ToBoolAndTrim()
|
||||||
{
|
{
|
||||||
if (StartsWith(LITERAL(T, '1'))
|
if (this->IsEmpty()) return false;
|
||||||
|| StartsWith(LITERAL(T, "true"))
|
|
||||||
|| StartsWith(LITERAL(T, "True"))
|
if (this->Front() == LITERAL(T, '1'))
|
||||||
|| StartsWith(LITERAL(T, "TRUE")))
|
|
||||||
{
|
{
|
||||||
|
RemovePrefix(1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StartsWith(LITERAL(T, '0'))
|
if (this->Front() == LITERAL(T, '0'))
|
||||||
|| StartsWith(LITERAL(T, "false"))
|
|
||||||
|| StartsWith(LITERAL(T, "False"))
|
|
||||||
|| StartsWith(LITERAL(T, "FALSE")))
|
|
||||||
{
|
{
|
||||||
|
RemovePrefix(1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ToInt() != 0;
|
if (StartsWith(LITERAL(T, "true"))
|
||||||
|
|| StartsWith(LITERAL(T, "True"))
|
||||||
|
|| StartsWith(LITERAL(T, "TRUE")))
|
||||||
|
{
|
||||||
|
RemovePrefix(4);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StartsWith(LITERAL(T, "false"))
|
||||||
|
|| StartsWith(LITERAL(T, "False"))
|
||||||
|
|| StartsWith(LITERAL(T, "FALSE")))
|
||||||
|
{
|
||||||
|
RemovePrefix(5);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToIntAndTrim() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <CCharType T>
|
template <CCharType T>
|
||||||
template <CIntegral U> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
template <CIntegral U> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||||
constexpr U TStringView<T>::ToInt(unsigned Base) const
|
constexpr U TStringView<T>::ToIntAndTrim(unsigned Base)
|
||||||
{
|
{
|
||||||
checkf(Base >= 2 && Base <= 36, TEXT("Illegal base. Please check the base."));
|
checkf(Base >= 2 && Base <= 36, TEXT("Illegal base. Please check the base."));
|
||||||
|
|
||||||
bool bNegative = false;
|
bool bNegative = false;
|
||||||
|
|
||||||
TStringView View = *this;
|
|
||||||
|
|
||||||
if constexpr (CSigned<U>)
|
if constexpr (CSigned<U>)
|
||||||
{
|
{
|
||||||
if (View.StartsWith(LITERAL(ElementType, '-')))
|
if (StartsWith(LITERAL(ElementType, '-')))
|
||||||
{
|
{
|
||||||
bNegative = true;
|
bNegative = true;
|
||||||
View.RemovePrefix(1);
|
RemovePrefix(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,9 +638,13 @@ constexpr U TStringView<T>::ToInt(unsigned Base) const
|
|||||||
UnsignedU LastValue = 0;
|
UnsignedU LastValue = 0;
|
||||||
UnsignedU Value = 0;
|
UnsignedU Value = 0;
|
||||||
|
|
||||||
for (ElementType Char : View)
|
bool bOverflow = false;
|
||||||
|
|
||||||
|
while (!this->IsEmpty())
|
||||||
{
|
{
|
||||||
auto Digit = TChar<ElementType>::ToDigit(Char);
|
auto Digit = TChar<ElementType>::ToDigit(this->Front());
|
||||||
|
|
||||||
|
RemovePrefix(1);
|
||||||
|
|
||||||
if (Digit >= Base) break;
|
if (Digit >= Base) break;
|
||||||
|
|
||||||
@ -640,7 +652,10 @@ constexpr U TStringView<T>::ToInt(unsigned Base) const
|
|||||||
|
|
||||||
Value = static_cast<UnsignedU>(LastValue * Base + Digit);
|
Value = static_cast<UnsignedU>(LastValue * Base + Digit);
|
||||||
|
|
||||||
if (Value < LastValue)
|
if (Value < LastValue) bOverflow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bOverflow)
|
||||||
{
|
{
|
||||||
if constexpr (CSigned<U>)
|
if constexpr (CSigned<U>)
|
||||||
{
|
{
|
||||||
@ -648,7 +663,6 @@ constexpr U TStringView<T>::ToInt(unsigned Base) const
|
|||||||
}
|
}
|
||||||
else return UnsignedMaximum;
|
else return UnsignedMaximum;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if constexpr (CSigned<U>)
|
if constexpr (CSigned<U>)
|
||||||
{
|
{
|
||||||
@ -663,7 +677,7 @@ constexpr U TStringView<T>::ToInt(unsigned Base) const
|
|||||||
|
|
||||||
template <CCharType T>
|
template <CCharType T>
|
||||||
template <CFloatingPoint U> requires (!CConst<U> && !CVolatile<U>)
|
template <CFloatingPoint U> requires (!CConst<U> && !CVolatile<U>)
|
||||||
constexpr U TStringView<T>::ToFloat(bool bFixed, bool bScientific) const
|
constexpr U TStringView<T>::ToFloatAndTrim(bool bFixed, bool bScientific)
|
||||||
{
|
{
|
||||||
NAMESPACE_STD::chars_format Format;
|
NAMESPACE_STD::chars_format Format;
|
||||||
|
|
||||||
@ -768,6 +782,8 @@ constexpr U TStringView<T>::ToFloat(bool bFixed, bool bScientific) const
|
|||||||
}
|
}
|
||||||
else ConvertResult = NAMESPACE_STD::from_chars(ToAddress(this->Begin()), ToAddress(this->End()), Result, Format);
|
else ConvertResult = NAMESPACE_STD::from_chars(ToAddress(this->Begin()), ToAddress(this->End()), Result, Format);
|
||||||
|
|
||||||
|
RemovePrefix(Iter - this->Begin());
|
||||||
|
|
||||||
if (ConvertResult.ec == NAMESPACE_STD::errc::result_out_of_range)
|
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();
|
||||||
|
@ -338,6 +338,78 @@ public:
|
|||||||
NODISCARD friend FORCEINLINE TString operator+( TStringView<ElementType> LHS, TString&& RHS) { RHS.Insert(0, LHS); return RHS; }
|
NODISCARD friend FORCEINLINE TString operator+( TStringView<ElementType> LHS, TString&& RHS) { RHS.Insert(0, LHS); return RHS; }
|
||||||
NODISCARD friend FORCEINLINE TString operator+(const TString<ElementType>& LHS, TString&& RHS) { RHS.Insert(0, LHS); return RHS; }
|
NODISCARD friend FORCEINLINE TString operator+(const TString<ElementType>& LHS, TString&& RHS) { RHS.Insert(0, LHS); return RHS; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Shrinks the view by moving its start forward. */
|
||||||
|
FORCEINLINE constexpr TString& RemovePrefix(size_t Count, bool bAllowShrinking = true)
|
||||||
|
{
|
||||||
|
checkf(Count <= this->Num(), TEXT("Illegal subview range. Please check Count."));
|
||||||
|
|
||||||
|
Erase(0, Count, bAllowShrinking);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Shrinks the view by moving its end backward. */
|
||||||
|
FORCEINLINE constexpr TString& RemoveSuffix(size_t Count, bool bAllowShrinking = true)
|
||||||
|
{
|
||||||
|
checkf(Count <= this->Num(), TEXT("Illegal subview range. Please check Count."));
|
||||||
|
|
||||||
|
this->SetNum(this->Num() - Count, bAllowShrinking);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes whitespace characters from the start of this string. */
|
||||||
|
FORCEINLINE constexpr TString& TrimStart(bool bAllowShrinking = true)
|
||||||
|
{
|
||||||
|
auto Index = Find([](ElementType Char) { return !TChar<ElementType>::IsSpace(Char); });
|
||||||
|
|
||||||
|
if (Index != INDEX_NONE)
|
||||||
|
{
|
||||||
|
RemovePrefix(Index, bAllowShrinking);
|
||||||
|
}
|
||||||
|
else this->Reset(bAllowShrinking);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes whitespace characters from the end of this string. */
|
||||||
|
FORCEINLINE constexpr TString& TrimEnd(bool bAllowShrinking = true)
|
||||||
|
{
|
||||||
|
auto Index = RFind([](ElementType Char) { return !TChar<ElementType>::IsSpace(Char); });
|
||||||
|
|
||||||
|
if (Index != INDEX_NONE)
|
||||||
|
{
|
||||||
|
this->SetNum(Index + 1, bAllowShrinking);
|
||||||
|
}
|
||||||
|
else this->Reset(bAllowShrinking);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes whitespace characters from the start and end of this string. */
|
||||||
|
FORCEINLINE constexpr TString& TrimStartAndEnd(bool bAllowShrinking = true)
|
||||||
|
{
|
||||||
|
TrimStart(false);
|
||||||
|
TrimEnd(bAllowShrinking);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes characters after the first null-terminator. */
|
||||||
|
FORCEINLINE constexpr TString& TrimToNullTerminator(bool bAllowShrinking = true)
|
||||||
|
{
|
||||||
|
auto Index = Find(LITERAL(ElementType, '\0'));
|
||||||
|
|
||||||
|
if (Index != INDEX_NONE)
|
||||||
|
{
|
||||||
|
this->SetNum(Index, bAllowShrinking);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** @return true if the string view starts with the given prefix, false otherwise. */
|
/** @return true if the string view starts with the given prefix, false otherwise. */
|
||||||
@ -1033,10 +1105,22 @@ public:
|
|||||||
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 can be fully represented as a boolean value, false otherwise. */
|
||||||
NODISCARD FORCEINLINE bool IsNumeric(unsigned Base = 10) const
|
NODISCARD FORCEINLINE bool IsBoolean() const
|
||||||
{
|
{
|
||||||
return TStringView<ElementType>(*this).IsNumeric(Base);
|
return TStringView<ElementType>(*this).IsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return true if the string can be fully represented as an integer value, false otherwise. */
|
||||||
|
NODISCARD FORCEINLINE bool IsInteger(unsigned Base = 10, bool bSigned = true) const
|
||||||
|
{
|
||||||
|
return TStringView<ElementType>(*this).IsInteger(Base, bSigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return true if the string can be fully represented as a floating-point value, false otherwise. */
|
||||||
|
NODISCARD FORCEINLINE bool IsFloatingPoint(bool bFixed = true, bool bScientific = true, bool bSigned = true) const
|
||||||
|
{
|
||||||
|
return TStringView<ElementType>(*this).IsFloatingPoint(bFixed, bScientific, bSigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -1207,10 +1291,54 @@ public:
|
|||||||
return TStringView<ElementType>(*this).template ToFloat<U>(bFixed, bScientific);
|
return TStringView<ElementType>(*this).template ToFloat<U>(bFixed, bScientific);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Converts a string into a boolean value and remove the parsed substring. */
|
||||||
|
NODISCARD FORCEINLINE bool ToBoolAndTrim()
|
||||||
|
{
|
||||||
|
TStringView<ElementType> View = *this;
|
||||||
|
|
||||||
|
bool Result = View.ToBool();
|
||||||
|
|
||||||
|
size_t TrimNum = this->Num() - View.Num();
|
||||||
|
|
||||||
|
if (TrimNum > 0) Erase(0, TrimNum);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Converts a string into an integer value and remove the parsed substring. */
|
||||||
|
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD FORCEINLINE U ToIntAndTrim(unsigned Base = 10)
|
||||||
|
{
|
||||||
|
TStringView<ElementType> View = *this;
|
||||||
|
|
||||||
|
U Result = View.template ToInt<U>(Base);
|
||||||
|
|
||||||
|
size_t TrimNum = this->Num() - View.Num();
|
||||||
|
|
||||||
|
if (TrimNum > 0) Erase(0, TrimNum);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Converts a string into a floating-point value and remove the parsed substring. */
|
||||||
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD FORCEINLINE U ToFloatAndTrim(bool bFixed = true, bool bScientific = true)
|
||||||
|
{
|
||||||
|
TStringView<ElementType> View = *this;
|
||||||
|
|
||||||
|
U Result = View.template ToFloat<U>(bFixed, bScientific);
|
||||||
|
|
||||||
|
size_t TrimNum = this->Num() - View.Num();
|
||||||
|
|
||||||
|
if (TrimNum > 0) Erase(0, TrimNum);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format some objects using a format string and append to the string.
|
* Format some objects using a format string.
|
||||||
*
|
*
|
||||||
* @param Fmt - The format string.
|
* @param Fmt - The format string.
|
||||||
* @param Args - The objects to format.
|
* @param Args - The objects to format.
|
||||||
@ -1218,7 +1346,18 @@ public:
|
|||||||
* @return The formatted string containing the objects.
|
* @return The formatted string containing the objects.
|
||||||
*/
|
*/
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
NODISCARD static TString Format(TStringView<ElementType> Fmt, const Ts&... Args);
|
NODISCARD static FORCEINLINE TString Format(TStringView<ElementType> Fmt, const Ts&... Args)
|
||||||
|
{
|
||||||
|
TString Result;
|
||||||
|
|
||||||
|
Result.AppendFormat(Fmt, Args...);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Format some objects using a format string and append to the string. */
|
||||||
|
template <typename... Ts>
|
||||||
|
void AppendFormat(TStringView<ElementType> Fmt, const Ts&... Args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a string using a format string to objects.
|
* Parse a string using a format string to objects.
|
||||||
@ -1234,6 +1373,21 @@ public:
|
|||||||
return TStringView(*this).Parse(Fmt, Args...);
|
return TStringView(*this).Parse(Fmt, Args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Parse a string using a format string to objects and remove the parsed substring. */
|
||||||
|
template <typename... Ts>
|
||||||
|
FORCEINLINE size_t ParseAndTrim(TStringView<ElementType> Fmt, Ts&... Args)
|
||||||
|
{
|
||||||
|
TStringView<ElementType> View = *this;
|
||||||
|
|
||||||
|
size_t Result = View.ParseAndTrim(Fmt, Args...);
|
||||||
|
|
||||||
|
size_t TrimNum = this->Num() - View.Num();
|
||||||
|
|
||||||
|
if (TrimNum > 0) Erase(0, TrimNum);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Overloads the GetTypeHash algorithm for TString. */
|
/** Overloads the GetTypeHash algorithm for TString. */
|
||||||
|
@ -113,22 +113,80 @@ public:
|
|||||||
NODISCARD friend constexpr auto operator<=>(TStringView LHS, ElementType RHS) { return LHS <=> TStringView(&RHS, 1); }
|
NODISCARD friend constexpr auto operator<=>(TStringView LHS, ElementType RHS) { return LHS <=> TStringView(&RHS, 1); }
|
||||||
NODISCARD friend constexpr auto operator<=>(ElementType LHS, TStringView RHS) { return TStringView(&LHS, 1) <=> RHS; }
|
NODISCARD friend constexpr auto operator<=>(ElementType LHS, TStringView RHS) { return TStringView(&LHS, 1) <=> RHS; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
/** Shrinks the view by moving its start forward. */
|
/** Shrinks the view by moving its start forward. */
|
||||||
FORCEINLINE constexpr void RemovePrefix(size_t Count)
|
FORCEINLINE constexpr TStringView RemovePrefix(size_t Count)
|
||||||
{
|
{
|
||||||
checkf(Count <= this->Num(), TEXT("Illegal subview range. Please check Count."));
|
checkf(Count <= this->Num(), TEXT("Illegal subview range. Please check Count."));
|
||||||
|
|
||||||
*this = Substr(Count);
|
*this = Substr(Count);
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Shrinks the view by moving its end backward. */
|
/** Shrinks the view by moving its end backward. */
|
||||||
FORCEINLINE constexpr void RemoveSuffix(size_t Count)
|
FORCEINLINE constexpr TStringView RemoveSuffix(size_t Count)
|
||||||
{
|
{
|
||||||
checkf(Count <= this->Num(), TEXT("Illegal subview range. Please check Count."));
|
checkf(Count <= this->Num(), TEXT("Illegal subview range. Please check Count."));
|
||||||
|
|
||||||
*this = Substr(0, this->Num() - Count);
|
*this = Substr(0, this->Num() - Count);
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Removes whitespace characters from the start of this string. */
|
||||||
|
FORCEINLINE constexpr TStringView TrimStart()
|
||||||
|
{
|
||||||
|
auto Index = Find([](ElementType Char) { return !TChar<ElementType>::IsSpace(Char); });
|
||||||
|
|
||||||
|
if (Index != INDEX_NONE)
|
||||||
|
{
|
||||||
|
RemovePrefix(Index);
|
||||||
|
}
|
||||||
|
else *this = TStringView();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes whitespace characters from the end of this string. */
|
||||||
|
FORCEINLINE constexpr TStringView TrimEnd()
|
||||||
|
{
|
||||||
|
auto Index = RFind([](ElementType Char) { return !TChar<ElementType>::IsSpace(Char); });
|
||||||
|
|
||||||
|
if (Index != INDEX_NONE)
|
||||||
|
{
|
||||||
|
RemoveSuffix(this->Num() - Index - 1);
|
||||||
|
}
|
||||||
|
else *this = TStringView();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes whitespace characters from the start and end of this string. */
|
||||||
|
FORCEINLINE constexpr TStringView TrimStartAndEnd()
|
||||||
|
{
|
||||||
|
TrimStart();
|
||||||
|
TrimEnd();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes characters after the first null-terminator. */
|
||||||
|
FORCEINLINE constexpr TStringView TrimToNullTerminator()
|
||||||
|
{
|
||||||
|
auto Index = Find(LITERAL(ElementType, '\0'));
|
||||||
|
|
||||||
|
if (Index != INDEX_NONE)
|
||||||
|
{
|
||||||
|
*this = Substr(0, Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
/** Copies the elements of this string view to the destination buffer without null-termination. */
|
/** Copies the elements of this string view to the destination buffer without null-termination. */
|
||||||
FORCEINLINE constexpr size_t Copy(ElementType* Dest, size_t Count = DynamicExtent, size_t Offset = 0) const
|
FORCEINLINE constexpr size_t Copy(ElementType* Dest, size_t Count = DynamicExtent, size_t Offset = 0) const
|
||||||
{
|
{
|
||||||
@ -401,15 +459,46 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return true if the string only contains numeric characters, false otherwise. */
|
/** @return true if the string can be fully represented as a boolean value, false otherwise. */
|
||||||
NODISCARD constexpr bool IsNumeric(unsigned Base = 10) const
|
NODISCARD FORCEINLINE constexpr bool IsBoolean() const
|
||||||
{
|
{
|
||||||
for (ElementType Char : *this)
|
TStringView View = *this;
|
||||||
{
|
|
||||||
if (!TChar<ElementType>::IsDigit(Char, Base)) return false;
|
Ignore = View.ToBoolAndTrim();
|
||||||
|
|
||||||
|
return View.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
/** @return true if the string can be fully represented as an integer value, false otherwise. */
|
||||||
|
NODISCARD FORCEINLINE constexpr bool IsInteger(unsigned Base = 10, bool bSigned = true) const
|
||||||
|
{
|
||||||
|
TStringView View = *this;
|
||||||
|
|
||||||
|
if (View.StartsWith(LITERAL(ElementType, '-')))
|
||||||
|
{
|
||||||
|
if (bSigned) View.RemovePrefix(1);
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ignore = View.ToIntAndTrim(Base);
|
||||||
|
|
||||||
|
return View.IsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return true if the string can be fully represented as a floating-point value, false otherwise. */
|
||||||
|
NODISCARD FORCEINLINE constexpr bool IsFloatingPoint(bool bFixed = true, bool bScientific = true, bool bSigned = true) const
|
||||||
|
{
|
||||||
|
TStringView View = *this;
|
||||||
|
|
||||||
|
if (View.StartsWith(LITERAL(ElementType, '-')))
|
||||||
|
{
|
||||||
|
if (bSigned) View.RemovePrefix(1);
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ignore = View.ToFloatAndTrim(bFixed, bScientific);
|
||||||
|
|
||||||
|
return View.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -422,7 +511,10 @@ public:
|
|||||||
*
|
*
|
||||||
* @return The boolean value.
|
* @return The boolean value.
|
||||||
*/
|
*/
|
||||||
NODISCARD constexpr bool ToBool() const;
|
NODISCARD constexpr bool ToBool() const
|
||||||
|
{
|
||||||
|
return TStringView(*this).ToBoolAndTrim();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a string into an integer value.
|
* Converts a string into an integer value.
|
||||||
@ -438,7 +530,10 @@ public:
|
|||||||
* @return The integer value.
|
* @return The integer value.
|
||||||
*/
|
*/
|
||||||
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||||
NODISCARD constexpr U ToInt(unsigned Base = 10) const;
|
NODISCARD constexpr U ToInt(unsigned Base = 10) const
|
||||||
|
{
|
||||||
|
return TStringView(*this).ToIntAndTrim<U>(Base);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a string into a floating-point value.
|
* Converts a string into a floating-point value.
|
||||||
@ -456,7 +551,21 @@ public:
|
|||||||
* @return The floating-point value.
|
* @return The floating-point value.
|
||||||
*/
|
*/
|
||||||
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
NODISCARD constexpr U ToFloat(bool bFixed = true, bool bScientific = true) const;
|
NODISCARD constexpr U ToFloat(bool bFixed = true, bool bScientific = true) const
|
||||||
|
{
|
||||||
|
return TStringView(*this).ToFloatAndTrim<U>(bFixed, bScientific);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Converts a string into a boolean value and remove the parsed substring. */
|
||||||
|
NODISCARD constexpr bool ToBoolAndTrim();
|
||||||
|
|
||||||
|
/** Converts a string into an integer value and remove the parsed substring. */
|
||||||
|
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD constexpr U ToIntAndTrim(unsigned Base = 10);
|
||||||
|
|
||||||
|
/** Converts a string into a floating-point value and remove the parsed substring. */
|
||||||
|
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||||
|
NODISCARD constexpr U ToFloatAndTrim(bool bFixed = true, bool bScientific = true);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -469,7 +578,14 @@ 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 Fmt, Ts&... Args) const;
|
size_t Parse(TStringView Fmt, Ts&... Args) const
|
||||||
|
{
|
||||||
|
return TStringView(*this).ParseAndTrim(Fmt, Args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse a string using a format string to objects and remove the parsed substring. */
|
||||||
|
template <typename... Ts>
|
||||||
|
size_t ParseAndTrim(TStringView Fmt, Ts&... Args);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user