refactor(string): refactor character and digit conversion to be non-invalidable
This commit is contained in:
parent
fe60fc33e0
commit
bc93455d0e
@ -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'), 16));
|
always_check(0x0 == TChar<T>::ToDigit(LITERAL(T, '0')));
|
||||||
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(0xF == TChar<T>::ToDigit(LITERAL(T, 'F')));
|
||||||
|
|
||||||
always_check(LITERAL(T, '0') == TChar<T>::FromDigit(0x0, 16));
|
always_check(LITERAL(T, '0') == TChar<T>::FromDigit(0x0));
|
||||||
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));
|
always_check(LITERAL(T, 'F') == TChar<T>::FromDigit(0xF));
|
||||||
};
|
};
|
||||||
|
|
||||||
Test(InPlaceType<char>);
|
Test(InPlaceType<char>);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreTypes.h"
|
#include "CoreTypes.h"
|
||||||
#include "Templates/Optional.h"
|
|
||||||
#include "TypeTraits/TypeTraits.h"
|
#include "TypeTraits/TypeTraits.h"
|
||||||
#include "Miscellaneous/AssertionMacros.h"
|
#include "Miscellaneous/AssertionMacros.h"
|
||||||
|
|
||||||
@ -809,7 +808,7 @@ struct TChar
|
|||||||
return InChar;
|
return InChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
NODISCARD FORCEINLINE static constexpr TOptional<unsigned> ToDigit(CharType InChar, unsigned Base = 10)
|
NODISCARD FORCEINLINE static constexpr unsigned ToDigit(CharType InChar)
|
||||||
{
|
{
|
||||||
static_assert(TChar::IsASCII());
|
static_assert(TChar::IsASCII());
|
||||||
|
|
||||||
@ -835,16 +834,23 @@ struct TChar
|
|||||||
|
|
||||||
static_assert(sizeof(DigitFromChar) == 256);
|
static_assert(sizeof(DigitFromChar) == 256);
|
||||||
|
|
||||||
if constexpr (sizeof(CharType) > 1) if (InChar >> 8) return Invalid;
|
if constexpr (sizeof(CharType) > 1) if (InChar >> 8) return DigitFromChar[0];
|
||||||
|
|
||||||
if (DigitFromChar[InChar] >= Base) return Invalid;
|
|
||||||
|
|
||||||
return DigitFromChar[InChar];
|
return DigitFromChar[InChar];
|
||||||
}
|
}
|
||||||
|
|
||||||
NODISCARD FORCEINLINE static constexpr TOptional<CharType> FromDigit(unsigned InDigit, unsigned Base = 10)
|
NODISCARD FORCEINLINE static constexpr CharType FromDigit(unsigned InDigit)
|
||||||
{
|
{
|
||||||
if (InDigit > Base) return Invalid;
|
checkf(InDigit < 36, TEXT("Digit must be in the range [0, 35]."));
|
||||||
|
|
||||||
|
return LITERAL(CharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit];
|
||||||
|
}
|
||||||
|
|
||||||
|
NODISCARD FORCEINLINE static constexpr CharType FromDigit(unsigned InDigit, bool bLowercase)
|
||||||
|
{
|
||||||
|
checkf(InDigit < 36, TEXT("Digit must be in the range [0, 35]."));
|
||||||
|
|
||||||
|
if (bLowercase) return LITERAL(CharType, "0123456789abcdefghijklmnopqrstuvwxyz")[InDigit];
|
||||||
|
|
||||||
return LITERAL(CharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit];
|
return LITERAL(CharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit];
|
||||||
}
|
}
|
||||||
|
@ -212,11 +212,11 @@ struct TStringHelper
|
|||||||
|
|
||||||
while (!View.IsEmpty())
|
while (!View.IsEmpty())
|
||||||
{
|
{
|
||||||
auto Digit = TChar<T>::ToDigit(View.Front(), Base);
|
auto Digit = TChar<T>::ToDigit(View.Front());
|
||||||
|
|
||||||
if (!Digit) break;
|
if (Digit >= Base) break;
|
||||||
|
|
||||||
Result = Result * static_cast<NumberType>(Base) + static_cast<NumberType>(*Digit);
|
Result = Result * static_cast<NumberType>(Base) + static_cast<NumberType>(Digit);
|
||||||
|
|
||||||
View.RemovePrefix(1);
|
View.RemovePrefix(1);
|
||||||
}
|
}
|
||||||
@ -632,13 +632,13 @@ constexpr U TStringView<T>::ToInt(unsigned Base) const
|
|||||||
|
|
||||||
for (ElementType Char : View)
|
for (ElementType Char : View)
|
||||||
{
|
{
|
||||||
auto Digit = TChar<ElementType>::ToDigit(Char, Base);
|
auto Digit = TChar<ElementType>::ToDigit(Char);
|
||||||
|
|
||||||
if (!Digit) break;
|
if (Digit >= Base) break;
|
||||||
|
|
||||||
LastValue = Value;
|
LastValue = Value;
|
||||||
|
|
||||||
Value = static_cast<UnsignedU>(LastValue * Base + *Digit);
|
Value = static_cast<UnsignedU>(LastValue * Base + Digit);
|
||||||
|
|
||||||
if (Value < LastValue)
|
if (Value < LastValue)
|
||||||
{
|
{
|
||||||
@ -794,7 +794,7 @@ void TString<T, Allocator>::AppendInt(U Value, 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."));
|
||||||
|
|
||||||
constexpr const ElementType* DigitToChar = LITERAL(ElementType, "0123456789ABCDEF");
|
static_assert(TChar<ElementType>::IsASCII());
|
||||||
|
|
||||||
using UnsignedU = TMakeUnsigned<U>;
|
using UnsignedU = TMakeUnsigned<U>;
|
||||||
|
|
||||||
@ -823,8 +823,8 @@ void TString<T, Allocator>::AppendInt(U Value, unsigned Base)
|
|||||||
case 0x02: do { *--Iter = static_cast<ElementType>('0' + (Unsigned & 0b00001)); Unsigned >>= 1; } while (Unsigned != 0); break;
|
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 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 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 0x10: do { *--Iter = TChar<ElementType>::FromDigit(Unsigned & 0b01111); Unsigned >>= 4; } while (Unsigned != 0); break;
|
||||||
case 0X20: do { *--Iter = DigitToChar[Unsigned & 0b11111]; Unsigned >>= 5; } while (Unsigned != 0); break;
|
case 0X20: do { *--Iter = TChar<ElementType>::FromDigit(Unsigned & 0b11111); Unsigned >>= 5; } while (Unsigned != 0); break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
case 5:
|
case 5:
|
||||||
@ -832,7 +832,7 @@ void TString<T, Allocator>::AppendInt(U Value, unsigned Base)
|
|||||||
case 7:
|
case 7:
|
||||||
case 9:
|
case 9:
|
||||||
case 10: do { *--Iter = static_cast<ElementType>('0' + Unsigned % Base); Unsigned = static_cast<UnsignedU>(Unsigned / Base); } while (Unsigned != 0); break;
|
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;
|
default: do { *--Iter = TChar<ElementType>::FromDigit(Unsigned % Base); Unsigned = static_cast<UnsignedU>(Unsigned / Base); } while (Unsigned != 0); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (CSigned<U>) if (bNegative) *--Iter = LITERAL(T, '-');
|
if constexpr (CSigned<U>) if (bNegative) *--Iter = LITERAL(T, '-');
|
||||||
@ -900,8 +900,8 @@ struct TStringFloatSerializer
|
|||||||
|
|
||||||
for (char& Char : Buffer)
|
for (char& Char : Buffer)
|
||||||
{
|
{
|
||||||
const auto Digit = FChar::ToDigit(Char, Base);
|
const auto Digit = FChar::ToDigit(Char);
|
||||||
if (Digit) Char = *FChar::FromDigit(*Digit, Base);
|
if (Digit < Base) Char = FChar::FromDigit(Digit);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result.Append(Buffer.Begin(), Buffer.End());
|
Result.Append(Buffer.Begin(), Buffer.End());
|
||||||
|
Loading…
Reference in New Issue
Block a user