fix(string): fix a potential error in the TCString due to short-circuit evaluation

This commit is contained in:
Redstone1024 2024-09-24 15:07:57 +08:00
parent 790b7fd5e6
commit d52f0c4df8

View File

@ -40,9 +40,9 @@ struct TCString
/** Copies one string to another. The size is used only for buffer safety and will not append null characters to the destination. */ /** Copies one string to another. The size is used only for buffer safety and will not append null characters to the destination. */
FORCEINLINE static CharType* Copy(CharType* Destination, size_t DestinationSize, const CharType* Source, size_t SourceSize) FORCEINLINE static CharType* Copy(CharType* Destination, size_t DestinationSize, const CharType* Source, size_t SourceSize)
{ {
checkf(Destination && Source, "Read access violation. Destination and source must not be nullptr."); checkf(Destination && Source, TEXT("Read access violation. Destination and source must not be nullptr."));
checkf(DestinationSize != 0 && SourceSize != 0, "Illegal buffer size. DestinationSize and SourceSize must not be zero."); checkf(DestinationSize != 0 && SourceSize != 0, TEXT("Illegal buffer size. DestinationSize and SourceSize must not be zero."));
if (DestinationSize == IGNORE_SIZE && SourceSize == IGNORE_SIZE) if (DestinationSize == IGNORE_SIZE && SourceSize == IGNORE_SIZE)
{ {
@ -73,9 +73,9 @@ struct TCString
/** Concatenates two strings. The size is used only for buffer safety and will not append null characters to the destination. */ /** Concatenates two strings. The size is used only for buffer safety and will not append null characters to the destination. */
FORCEINLINE static CharType* Cat(CharType* Destination, size_t DestinationSize, const CharType* Source, size_t SourceSize) FORCEINLINE static CharType* Cat(CharType* Destination, size_t DestinationSize, const CharType* Source, size_t SourceSize)
{ {
checkf(Destination && Source, "Read access violation. Destination and source must not be nullptr."); checkf(Destination && Source, TEXT("Read access violation. Destination and source must not be nullptr."));
checkf(DestinationSize != 0 && SourceSize != 0, "Illegal buffer size. DestinationSize and SourceSize must not be zero."); checkf(DestinationSize != 0 && SourceSize != 0, TEXT("Illegal buffer size. DestinationSize and SourceSize must not be zero."));
if (DestinationSize == IGNORE_SIZE && SourceSize == IGNORE_SIZE) if (DestinationSize == IGNORE_SIZE && SourceSize == IGNORE_SIZE)
{ {
@ -99,9 +99,9 @@ struct TCString
/** @return The length of a given string. The maximum length is the buffer size. */ /** @return The length of a given string. The maximum length is the buffer size. */
NODISCARD FORCEINLINE static size_t Length(const CharType* InString, size_t SourceSize) NODISCARD FORCEINLINE static size_t Length(const CharType* InString, size_t SourceSize)
{ {
checkf(InString, "Read access violation. InString must not be nullptr."); checkf(InString, TEXT("Read access violation. InString must not be nullptr."));
checkf(SourceSize != 0, "Illegal buffer size. SourceSize must not be zero."); checkf(SourceSize != 0, TEXT("Illegal buffer size. SourceSize must not be zero."));
if (SourceSize == IGNORE_SIZE) if (SourceSize == IGNORE_SIZE)
{ {
@ -117,9 +117,11 @@ struct TCString
size_t Result = 0; size_t Result = 0;
while (*InString++ != LITERAL(CharType, '\0') && SourceSize--) while (*InString != LITERAL(CharType, '\0') && SourceSize != 0)
{ {
++Result; ++Result;
++InString;
--SourceSize;
} }
return Result; return Result;
@ -128,9 +130,9 @@ struct TCString
/** Compares two strings. The size is used only for buffer safety not for comparison. */ /** Compares two strings. The size is used only for buffer safety not for comparison. */
NODISCARD FORCEINLINE static strong_ordering Compare(const CharType* LHS, size_t LHSSize, const CharType* RHS, size_t RHSSize) NODISCARD FORCEINLINE static strong_ordering Compare(const CharType* LHS, size_t LHSSize, const CharType* RHS, size_t RHSSize)
{ {
checkf(LHS && RHS, "Read access violation. LHS and RHS must not be nullptr."); checkf(LHS && RHS, TEXT("Read access violation. LHS and RHS must not be nullptr."));
checkf(LHSSize != 0 && RHSSize != 0, "Illegal buffer size. LHSSize and RHSSize must not be zero."); checkf(LHSSize != 0 && RHSSize != 0, TEXT("Illegal buffer size. LHSSize and RHSSize must not be zero."));
if (LHSSize == IGNORE_SIZE && RHSSize == IGNORE_SIZE) if (LHSSize == IGNORE_SIZE && RHSSize == IGNORE_SIZE)
{ {
@ -144,37 +146,48 @@ struct TCString
} }
} }
while (LHSSize-- && RHSSize--) while (LHSSize != 0 && RHSSize != 0)
{ {
if (*LHS != *RHS) if (*LHS != *RHS)
{ {
return *LHS <=> *RHS; return *LHS <=> *RHS;
} }
if (*LHS++ == LITERAL(CharType, '\0') || *RHS++ == LITERAL(CharType, '\0')) break; if (*LHS == LITERAL(CharType, '\0') && *RHS == LITERAL(CharType, '\0'))
{
return strong_ordering::equal;
} }
return strong_ordering::equal; ++LHS;
++RHS;
--LHSSize;
--RHSSize;
}
return LHSSize <=> RHSSize;
} }
/** Finds the first or last occurrence of a character that satisfies the predicate. The terminating null character is considered to be a part of the string. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a character that satisfies the predicate. The terminating null character is considered to be a part of the string. The size is used only for buffer safety. */
template <CPredicate<CharType> F> template <CPredicate<CharType> F>
NODISCARD FORCEINLINE static const CharType* Find(const CharType* InString, size_t BufferSize, F&& InPredicate, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static const CharType* Find(const CharType* InString, size_t BufferSize, F&& InPredicate, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString, "Read access violation. InString must not be nullptr."); checkf(InString, TEXT("Read access violation. InString must not be nullptr."));
checkf(BufferSize != 0, "Illegal buffer size. BufferSize must not be zero."); checkf(BufferSize != 0, TEXT("Illegal buffer size. BufferSize must not be zero."));
if (SearchDirection == ESearchDirection::FromStart) if (SearchDirection == ESearchDirection::FromStart)
{ {
while (BufferSize--) while (BufferSize != 0)
{ {
if (InvokeResult<bool>(Forward<F>(InPredicate), *InString)) if (InvokeResult<bool>(Forward<F>(InPredicate), *InString))
{ {
return InString; return InString;
} }
if (*InString++ == LITERAL(CharType, '\0')) break; if (*InString == LITERAL(CharType, '\0')) break;
++InString;
--BufferSize;
} }
} }
else else
@ -190,7 +203,9 @@ struct TCString
return InString + Index; return InString + Index;
} }
if (!Index--) break; if (Index == 0) break;
--Index;
} }
} }
@ -201,9 +216,9 @@ struct TCString
template <CPredicate<CharType> F> template <CPredicate<CharType> F>
NODISCARD FORCEINLINE static CharType* Find( CharType* InString, size_t BufferSize, F&& InPredicate, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static CharType* Find( CharType* InString, size_t BufferSize, F&& InPredicate, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString, "Read access violation. InString must not be nullptr."); checkf(InString, TEXT("Read access violation. InString must not be nullptr."));
checkf(BufferSize != 0, "Illegal buffer size. BufferSize must not be zero."); checkf(BufferSize != 0, TEXT("Illegal buffer size. BufferSize must not be zero."));
check_no_recursion(); check_no_recursion();
@ -213,9 +228,9 @@ struct TCString
/** Finds the first or last occurrence of a character. The terminating null character is considered to be a part of the string. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a character. The terminating null character is considered to be a part of the string. The size is used only for buffer safety. */
NODISCARD FORCEINLINE static const CharType* FindChar(const CharType* InString, size_t BufferSize, CharType Character, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static const CharType* FindChar(const CharType* InString, size_t BufferSize, CharType Character, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString, "Read access violation. InString must not be nullptr."); checkf(InString, TEXT("Read access violation. InString must not be nullptr."));
checkf(BufferSize != 0, "Illegal buffer size. BufferSize must not be zero."); checkf(BufferSize != 0, TEXT("Illegal buffer size. BufferSize must not be zero."));
if (BufferSize == IGNORE_SIZE) if (BufferSize == IGNORE_SIZE)
{ {
@ -235,9 +250,9 @@ struct TCString
/** Finds the first or last occurrence of a character. The terminating null character is considered to be a part of the string. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a character. The terminating null character is considered to be a part of the string. The size is used only for buffer safety. */
NODISCARD FORCEINLINE static CharType* FindChar( CharType* InString, size_t BufferSize, CharType Character, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static CharType* FindChar( CharType* InString, size_t BufferSize, CharType Character, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString, "Read access violation. InString must not be nullptr."); checkf(InString, TEXT("Read access violation. InString must not be nullptr."));
checkf(BufferSize != 0, "Illegal buffer size. BufferSize must not be zero."); checkf(BufferSize != 0, TEXT("Illegal buffer size. BufferSize must not be zero."));
check_no_recursion(); check_no_recursion();
@ -247,9 +262,9 @@ struct TCString
/** Finds the first or last occurrence of a character in a charset. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a character in a charset. The size is used only for buffer safety. */
NODISCARD FORCEINLINE static const CharType* FindChar(const CharType* InString, size_t BufferSize, const CharType* Charset, size_t CharsetSize, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static const CharType* FindChar(const CharType* InString, size_t BufferSize, const CharType* Charset, size_t CharsetSize, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString && Charset, "Read access violation. InString and Charset must not be nullptr."); checkf(InString && Charset, TEXT("Read access violation. InString and Charset must not be nullptr."));
checkf(BufferSize != 0 && CharsetSize != 0, "Illegal buffer size. BufferSize and CharsetSize must not be zero."); checkf(BufferSize != 0 && CharsetSize != 0, TEXT("Illegal buffer size. BufferSize and CharsetSize must not be zero."));
if (BufferSize == IGNORE_SIZE && CharsetSize == IGNORE_SIZE && SearchDirection == ESearchDirection::FromStart) if (BufferSize == IGNORE_SIZE && CharsetSize == IGNORE_SIZE && SearchDirection == ESearchDirection::FromStart)
{ {
@ -278,9 +293,9 @@ struct TCString
/** Finds the first or last occurrence of a character in a charset. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a character in a charset. The size is used only for buffer safety. */
NODISCARD FORCEINLINE static CharType* FindChar( CharType* InString, size_t BufferSize, const CharType* Charset, size_t CharsetSize, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static CharType* FindChar( CharType* InString, size_t BufferSize, const CharType* Charset, size_t CharsetSize, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString && Charset, "Read access violation. InString and Charset must not be nullptr."); checkf(InString && Charset, TEXT("Read access violation. InString and Charset must not be nullptr."));
checkf(BufferSize != 0 && CharsetSize != 0, "Illegal buffer size. BufferSize and CharsetSize must not be zero."); checkf(BufferSize != 0 && CharsetSize != 0, TEXT("Illegal buffer size. BufferSize and CharsetSize must not be zero."));
check_no_recursion(); check_no_recursion();
@ -290,9 +305,9 @@ struct TCString
/** Finds the first or last occurrence of a character that is not the given character. The terminating null character is considered to be a part of the string. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a character that is not the given character. The terminating null character is considered to be a part of the string. The size is used only for buffer safety. */
NODISCARD FORCEINLINE static const CharType* FindNotChar(const CharType* InString, size_t BufferSize, CharType Character, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static const CharType* FindNotChar(const CharType* InString, size_t BufferSize, CharType Character, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString, "Read access violation. InString must not be nullptr."); checkf(InString, TEXT("Read access violation. InString must not be nullptr."));
checkf(BufferSize != 0, "Illegal buffer size. BufferSize must not be zero."); checkf(BufferSize != 0, TEXT("Illegal buffer size. BufferSize must not be zero."));
if (Character == LITERAL(CharType, '\0') && SearchDirection == ESearchDirection::FromStart) if (Character == LITERAL(CharType, '\0') && SearchDirection == ESearchDirection::FromStart)
{ {
@ -319,9 +334,9 @@ struct TCString
/** Finds the first or last occurrence of a character that is not the given character. The terminating null character is considered to be a part of the string. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a character that is not the given character. The terminating null character is considered to be a part of the string. The size is used only for buffer safety. */
NODISCARD FORCEINLINE static CharType* FindNotChar( CharType* InString, size_t BufferSize, CharType Character, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static CharType* FindNotChar( CharType* InString, size_t BufferSize, CharType Character, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString, "Read access violation. InString must not be nullptr."); checkf(InString, TEXT("Read access violation. InString must not be nullptr."));
checkf(BufferSize != 0, "Illegal buffer size. BufferSize must not be zero."); checkf(BufferSize != 0, TEXT("Illegal buffer size. BufferSize must not be zero."));
check_no_recursion(); check_no_recursion();
@ -331,9 +346,9 @@ struct TCString
/** Finds the first or last occurrence of a character that is not in the given charset. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a character that is not in the given charset. The size is used only for buffer safety. */
NODISCARD FORCEINLINE static const CharType* FindNotChar(const CharType* InString, size_t BufferSize, const CharType* Charset, size_t CharsetSize, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static const CharType* FindNotChar(const CharType* InString, size_t BufferSize, const CharType* Charset, size_t CharsetSize, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString && Charset, "Read access violation. InString and Charset must not be nullptr."); checkf(InString && Charset, TEXT("Read access violation. InString and Charset must not be nullptr."));
checkf(BufferSize != 0 && CharsetSize != 0, "Illegal buffer size. BufferSize and CharsetSize must not be zero."); checkf(BufferSize != 0 && CharsetSize != 0, TEXT("Illegal buffer size. BufferSize and CharsetSize must not be zero."));
if (BufferSize == IGNORE_SIZE && CharsetSize == IGNORE_SIZE && SearchDirection == ESearchDirection::FromStart) if (BufferSize == IGNORE_SIZE && CharsetSize == IGNORE_SIZE && SearchDirection == ESearchDirection::FromStart)
{ {
@ -355,9 +370,9 @@ struct TCString
/** Finds the first or last occurrence of a character that is not in the given charset. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a character that is not in the given charset. The size is used only for buffer safety. */
NODISCARD FORCEINLINE static CharType* FindNotChar( CharType* InString, size_t BufferSize, const CharType* Charset, size_t CharsetSize, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static CharType* FindNotChar( CharType* InString, size_t BufferSize, const CharType* Charset, size_t CharsetSize, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString && Charset, "Read access violation. InString and Charset must not be nullptr."); checkf(InString && Charset, TEXT("Read access violation. InString and Charset must not be nullptr."));
checkf(BufferSize != 0 && CharsetSize != 0, "Illegal buffer size. BufferSize and CharsetSize must not be zero."); checkf(BufferSize != 0 && CharsetSize != 0, TEXT("Illegal buffer size. BufferSize and CharsetSize must not be zero."));
check_no_recursion(); check_no_recursion();
@ -365,11 +380,11 @@ struct TCString
} }
/** Finds the first or last occurrence of a substring. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a substring. The size is used only for buffer safety. */
NODISCARD FORCEINLINE static const CharType* FindString(const CharType* InString, size_t BufferSize, const CharType* Substring, size_t SubstringSize, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD static const CharType* FindString(const CharType* InString, size_t BufferSize, const CharType* Substring, size_t SubstringSize, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString && Substring, "Read access violation. InString and Substring must not be nullptr."); checkf(InString && Substring, TEXT("Read access violation. InString and Substring must not be nullptr."));
checkf(BufferSize != 0 && SubstringSize != 0, "Illegal buffer size. BufferSize and SubstringSize must not be zero."); checkf(BufferSize != 0 && SubstringSize != 0, TEXT("Illegal buffer size. BufferSize and SubstringSize must not be zero."));
if (*Substring == LITERAL(CharType, '\0')) if (*Substring == LITERAL(CharType, '\0'))
{ {
@ -423,9 +438,9 @@ struct TCString
/** Finds the first or last occurrence of a substring. The size is used only for buffer safety. */ /** Finds the first or last occurrence of a substring. The size is used only for buffer safety. */
NODISCARD FORCEINLINE static CharType* FindString( CharType* InString, size_t BufferSize, const CharType* Substring, size_t SubstringSize, ESearchDirection SearchDirection = ESearchDirection::FromStart) NODISCARD FORCEINLINE static CharType* FindString( CharType* InString, size_t BufferSize, const CharType* Substring, size_t SubstringSize, ESearchDirection SearchDirection = ESearchDirection::FromStart)
{ {
checkf(InString && Substring, "Read access violation. InString and Substring must not be nullptr."); checkf(InString && Substring, TEXT("Read access violation. InString and Substring must not be nullptr."));
checkf(BufferSize != 0 && SubstringSize != 0, "Illegal buffer size. BufferSize and SubstringSize must not be zero."); checkf(BufferSize != 0 && SubstringSize != 0, TEXT("Illegal buffer size. BufferSize and SubstringSize must not be zero."));
check_no_recursion(); check_no_recursion();