refactor(*): refactor the tool library's parent folder to plural form
This commit is contained in:
931
Redcraft.Utility/Source/Public/Strings/Char.h
Normal file
931
Redcraft.Utility/Source/Public/Strings/Char.h
Normal file
@ -0,0 +1,931 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
#include <locale>
|
||||
#include <climits>
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
template <typename T>
|
||||
concept CCharType = CSameAs<T, char> || CSameAs<T, wchar> || CSameAs<T, u8char> || CSameAs<T, u16char> || CSameAs<T, u32char>;
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <CCharType>
|
||||
struct TLiteral;
|
||||
|
||||
template <>
|
||||
struct TLiteral<char>
|
||||
{
|
||||
NODISCARD FORCEINLINE static constexpr char Select(const char X, const wchar , const u8char , const u16char , const u32char ) { return X; }
|
||||
NODISCARD FORCEINLINE static constexpr const char* Select(const char* X, const wchar*, const u8char*, const u16char*, const u32char*) { return X; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TLiteral<wchar>
|
||||
{
|
||||
NODISCARD FORCEINLINE static constexpr wchar Select(const char , const wchar X, const u8char , const u16char , const u32char ) { return X; }
|
||||
NODISCARD FORCEINLINE static constexpr const wchar* Select(const char*, const wchar* X, const u8char*, const u16char*, const u32char*) { return X; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TLiteral<u8char>
|
||||
{
|
||||
NODISCARD FORCEINLINE static constexpr u8char Select(const char , const wchar , const u8char X, const u16char , const u32char ) { return X; }
|
||||
NODISCARD FORCEINLINE static constexpr const u8char* Select(const char*, const wchar*, const u8char* X, const u16char*, const u32char*) { return X; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TLiteral<u16char>
|
||||
{
|
||||
NODISCARD FORCEINLINE static constexpr u16char Select(const char , const wchar , const u8char , const u16char X, const u32char ) { return X; }
|
||||
NODISCARD FORCEINLINE static constexpr const u16char* Select(const char*, const wchar*, const u8char*, const u16char* X, const u32char*) { return X; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TLiteral<u32char>
|
||||
{
|
||||
NODISCARD FORCEINLINE static constexpr u32char Select(const char , const wchar , const u8char , const u16char , const u32char X) { return X; }
|
||||
NODISCARD FORCEINLINE static constexpr const u32char* Select(const char*, const wchar*, const u8char*, const u16char*, const u32char* X) { return X; }
|
||||
};
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
/** Templated literal struct to allow selection of string literals based on the character type provided, and not on compiler switches. */
|
||||
#define LITERAL(CharType, StringLiteral) NAMESPACE_REDCRAFT::NAMESPACE_PRIVATE::TLiteral<CharType>::Select(TEXT(StringLiteral), WTEXT(StringLiteral), U8TEXT(StringLiteral), U16TEXT(StringLiteral), U32TEXT(StringLiteral))
|
||||
|
||||
static_assert(CUnsigned<u8char>, "TChar assumes u8char is an unsigned integer");
|
||||
static_assert(CUnsigned<u16char>, "TChar assumes u16char is an unsigned integer");
|
||||
static_assert(CUnsigned<u32char>, "TChar assumes u32char is an unsigned integer");
|
||||
static_assert(CUnsigned<unicodechar>, "TChar assumes unicodechar is an unsigned integer");
|
||||
|
||||
/** Set of utility functions operating on a single character. Implemented based on user-preferred locale and ISO 30112 "i18n". */
|
||||
template <CCharType T>
|
||||
struct TChar
|
||||
{
|
||||
using FCharType = T;
|
||||
|
||||
/** The maximum number of code units required to represent a single character. if unknown, guess 1. */
|
||||
static constexpr size_t MaxCodeUnitLength =
|
||||
CSameAs<FCharType, char> ? MB_LEN_MAX :
|
||||
CSameAs<FCharType, wchar> ?
|
||||
PLATFORM_WINDOWS ? 2 :
|
||||
PLATFORM_LINUX ? 1 : 1 :
|
||||
CSameAs<FCharType, u8char> ? 4 :
|
||||
CSameAs<FCharType, u16char> ? 2 :
|
||||
CSameAs<FCharType, u32char> ? 1 : 1;
|
||||
|
||||
/** Whether the character type is fixed-length. */
|
||||
static constexpr bool bIsFixedLength = MaxCodeUnitLength == 1;
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsValid(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
if ((InChar & 0b10000000) == 0b00000000) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char> || CSameAs<FCharType, u32char>)
|
||||
{
|
||||
if (InChar >= 0xD800 && InChar <= 0xDBFF) return false;
|
||||
if (InChar >= 0xDC00 && InChar <= 0xDFFF) return false;
|
||||
|
||||
return InChar <= 0x10FFFF;
|
||||
}
|
||||
|
||||
// Windows uses UTF-16 encoding for wchar.
|
||||
else if constexpr (PLATFORM_WINDOWS && (CSameAs<FCharType, wchar>))
|
||||
{
|
||||
return TChar::IsValid(static_cast<u16char>(InChar));
|
||||
}
|
||||
|
||||
// Linux uses UTF-32 encoding for wchar.
|
||||
else if constexpr (PLATFORM_LINUX && (CSameAs<FCharType, wchar>))
|
||||
{
|
||||
return TChar::IsValid(static_cast<u32char>(InChar));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsNonch(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
if (InChar >= U16TEXT('\uFDD0') && InChar <= U16TEXT('\uFDEF')) return true;
|
||||
|
||||
if (InChar == U16TEXT('\uFFFE')) return true;
|
||||
if (InChar == U16TEXT('\uFFFF')) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
if (InChar >= U32TEXT('\uFDD0') && InChar <= U32TEXT('\uFDEF')) return true;
|
||||
|
||||
if ((InChar & 0x0000FFFE) == 0x0000FFFE) return TChar::IsValid(InChar);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Windows uses UTF-16 encoding for wchar.
|
||||
else if constexpr (PLATFORM_WINDOWS && (CSameAs<FCharType, wchar>))
|
||||
{
|
||||
return TChar::IsNonch(static_cast<u16char>(InChar));
|
||||
}
|
||||
|
||||
// Linux uses UTF-32 encoding for wchar.
|
||||
else if constexpr (PLATFORM_LINUX && (CSameAs<FCharType, wchar>))
|
||||
{
|
||||
return TChar::IsNonch(static_cast<u32char>(InChar));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsASCII(FCharType InChar = LITERAL(FCharType, '\0'))
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char>)
|
||||
{
|
||||
constexpr bool ASCIICompatible = []() -> bool
|
||||
{
|
||||
constexpr char ASCIITable[] =
|
||||
TEXT("\u0000\u0001\u0002\u0003\u0004\u0005\u0006")
|
||||
TEXT("\a\b\t\n\v\f\r")
|
||||
TEXT("\u000E\u000F")
|
||||
TEXT("\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017")
|
||||
TEXT("\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F")
|
||||
TEXT(" !\"#$%&'()*+,-./0123456789:;<=>?")
|
||||
TEXT("@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_")
|
||||
TEXT("`abcdefghijklmnopqrstuvwxyz{|}~\u007F");
|
||||
|
||||
for (size_t Index = 0; Index <= 0x7F; ++Index)
|
||||
{
|
||||
if (ASCIITable[Index] != static_cast<char>(Index)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
();
|
||||
|
||||
return ASCIICompatible && 0x00 <= InChar && InChar <= 0x7F;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, wchar>)
|
||||
{
|
||||
constexpr bool ASCIICompatible = []() -> bool
|
||||
{
|
||||
constexpr wchar ASCIITable[] =
|
||||
WTEXT("\u0000\u0001\u0002\u0003\u0004\u0005\u0006")
|
||||
WTEXT("\a\b\t\n\v\f\r")
|
||||
WTEXT("\u000E\u000F")
|
||||
WTEXT("\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017")
|
||||
WTEXT("\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F")
|
||||
WTEXT(" !\"#$%&'()*+,-./0123456789:;<=>?")
|
||||
WTEXT("@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_")
|
||||
WTEXT("`abcdefghijklmnopqrstuvwxyz{|}~\u007F");
|
||||
|
||||
for (size_t Index = 0; Index <= 0x7F; ++Index)
|
||||
{
|
||||
if (ASCIITable[Index] != static_cast<wchar>(Index)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
();
|
||||
|
||||
return ASCIICompatible && 0x00 <= InChar && InChar <= 0x7F;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char> || CSameAs<FCharType, u16char> || CSameAs<FCharType, u32char> || CSameAs<FCharType, unicodechar>)
|
||||
{
|
||||
return InChar <= 0x7F;
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsAlnum(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return NAMESPACE_STD::isalnum(InChar, Loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
return TChar::IsAlpha(InChar) || TChar::IsDigit(InChar);
|
||||
}
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsAlpha(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return NAMESPACE_STD::isalpha(InChar, Loc);
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* <U0041>..<U005A>;<U0061>..<U007A>;
|
||||
*/
|
||||
if ((InChar >= U8TEXT('\u0041') && InChar <= U8TEXT('\u005A')) ||
|
||||
(InChar >= U8TEXT('\u0061') && InChar <= U8TEXT('\u007A')))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char> || CSameAs<FCharType, u32char>)
|
||||
{
|
||||
checkf(InChar <= LITERAL(FCharType, '\u007F'), TEXT("TChar::IsAlpha() only supports basic latin block."));
|
||||
|
||||
if (InChar > LITERAL(FCharType, '\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsAlpha(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsLower(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return NAMESPACE_STD::islower(InChar, Loc);
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* <U0061>..<U007A>;
|
||||
*/
|
||||
if (InChar >= U8TEXT('\u0061') && InChar <= U8TEXT('\u007A')) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsLower() only supports basic latin block."));
|
||||
|
||||
if (InChar > U16TEXT('\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsLower(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsLower() only supports basic latin block."));
|
||||
|
||||
if (InChar > U32TEXT('\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsLower(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsUpper(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return NAMESPACE_STD::isupper(InChar, Loc);
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* <U0041>..<U005A>;
|
||||
*/
|
||||
if (InChar >= U8TEXT('\u0041') && InChar <= U8TEXT('\u005A')) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsUpper() only supports basic latin block."));
|
||||
|
||||
if (InChar > U16TEXT('\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsUpper(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsUpper() only supports basic latin block."));
|
||||
|
||||
if (InChar > U32TEXT('\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsUpper(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsDigit(FCharType InChar)
|
||||
{
|
||||
static_assert(TChar::IsASCII());
|
||||
|
||||
/* <U0030>..<U0039>; */
|
||||
return InChar >= LITERAL(FCharType, '0') && InChar <= LITERAL(FCharType, '9');
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsDigit(FCharType InChar, unsigned Base)
|
||||
{
|
||||
checkf(Base >= 2 && Base <= 36, TEXT("Base must be in the range [2, 36]."));
|
||||
|
||||
static_assert(TChar::IsASCII());
|
||||
|
||||
bool bResult = false;
|
||||
|
||||
/* <U0030>..<U0039>; */
|
||||
bResult |= InChar >= LITERAL(FCharType, '0') && InChar < LITERAL(FCharType, '0') + static_cast<signed>(Base);
|
||||
|
||||
/* <U0041>..<U0046>; */
|
||||
bResult |= InChar >= LITERAL(FCharType, 'a') && InChar < LITERAL(FCharType, 'a') + static_cast<signed>(Base) - 10;
|
||||
|
||||
/* <U0061>..<U0066>; */
|
||||
bResult |= InChar >= LITERAL(FCharType, 'A') && InChar < LITERAL(FCharType, 'A') + static_cast<signed>(Base) - 10;
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsCntrl(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return NAMESPACE_STD::iscntrl(InChar, Loc);
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/* <U0000>..<U001F>;<U007F>; */
|
||||
return (InChar >= U8TEXT('\u0000') && InChar <= U8TEXT('\u001F')) || InChar == U8TEXT('\u007F');
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
/* <U0000>..<U001F>;<U007F>..<U009F>;<U2028>;<U2029>; */
|
||||
return
|
||||
(InChar >= U16TEXT('\u0000') && InChar <= U16TEXT('\u001F')) ||
|
||||
(InChar >= U16TEXT('\u007F') && InChar <= U16TEXT('\u009F')) ||
|
||||
(InChar == U16TEXT('\u2028') || InChar == U16TEXT('\u2029'));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
/* <U0000>..<U001F>;<U007F>..<U009F>;<U2028>;<U2029>; */
|
||||
return
|
||||
(InChar >= U32TEXT('\u0000') && InChar <= U32TEXT('\u001F')) ||
|
||||
(InChar >= U32TEXT('\u007F') && InChar <= U32TEXT('\u009F')) ||
|
||||
(InChar == U32TEXT('\u2028') || InChar == U32TEXT('\u2029'));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsGraph(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return NAMESPACE_STD::isgraph(InChar, Loc);
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* <U0021>..<U007E>;
|
||||
*/
|
||||
if (InChar >= U8TEXT('\u0021') && InChar <= U8TEXT('\u007E')) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsGraph() only supports basic latin block."));
|
||||
|
||||
if (InChar > U16TEXT('\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsGraph(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsGraph() only supports basic latin block."));
|
||||
|
||||
if (InChar > U32TEXT('\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsGraph(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsSpace(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return NAMESPACE_STD::isspace(InChar, Loc);
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/*
|
||||
* ISO/IEC 6429
|
||||
* <U0009>..<U000D>;
|
||||
*/
|
||||
if (InChar >= U8TEXT('\u0009') && InChar <= U8TEXT('\u000D')) return true;
|
||||
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* <U0020>;
|
||||
*/
|
||||
if (InChar == U8TEXT('\u0020')) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
/*
|
||||
* ISO/IEC 6429
|
||||
* <U0009>..<U000D>;
|
||||
*/
|
||||
if (InChar >= U16TEXT('\u0009') && InChar <= U16TEXT('\u000D')) return true;
|
||||
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* <U0020>;
|
||||
*/
|
||||
if (InChar == U16TEXT('\u0020')) return true;
|
||||
|
||||
/*
|
||||
* OGHAM
|
||||
* <U1680>;
|
||||
*/
|
||||
if (InChar == U16TEXT('\u1680')) return true;
|
||||
|
||||
/*
|
||||
* MONGOL
|
||||
* <U180E>;
|
||||
*/
|
||||
if (InChar == U16TEXT('\u180E')) return true;
|
||||
|
||||
/*
|
||||
* GENERAL PUNCTUATION
|
||||
* <U2000>..<U2006>;<U2008>..<U200A>;<U2028>;<U2029>;<U205F>;
|
||||
*/
|
||||
if ((InChar >= U16TEXT('\u2000') && InChar <= U16TEXT('\u2006')) ||
|
||||
(InChar >= U16TEXT('\u2008') && InChar <= U16TEXT('\u200A')) ||
|
||||
(InChar == U16TEXT('\u2028') || InChar == U16TEXT('\u2029')) ||
|
||||
(InChar == U16TEXT('\u205F')))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* CJK SYMBOLS AND PUNCTUATION, HIRAGANA
|
||||
* <U3000>;
|
||||
*/
|
||||
if (InChar == U16TEXT('\u3000')) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
/*
|
||||
* ISO/IEC 6429
|
||||
* <U0009>..<U000D>;
|
||||
*/
|
||||
if (InChar >= U32TEXT('\u0009') && InChar <= U32TEXT('\u000D')) return true;
|
||||
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* <U0020>;
|
||||
*/
|
||||
if (InChar == U32TEXT('\u0020')) return true;
|
||||
|
||||
/*
|
||||
* OGHAM
|
||||
* <U1680>;
|
||||
*/
|
||||
if (InChar == U32TEXT('\u1680')) return true;
|
||||
|
||||
/*
|
||||
* MONGOL
|
||||
* <U180E>;
|
||||
*/
|
||||
if (InChar == U32TEXT('\u180E')) return true;
|
||||
|
||||
/*
|
||||
* GENERAL PUNCTUATION
|
||||
* <U2000>..<U2006>;<U2008>..<U200A>;<U2028>;<U2029>;<U205F>;
|
||||
*/
|
||||
if ((InChar >= U32TEXT('\u2000') && InChar <= U32TEXT('\u2006')) ||
|
||||
(InChar >= U32TEXT('\u2008') && InChar <= U32TEXT('\u200A')) ||
|
||||
(InChar == U32TEXT('\u2028') || InChar == U32TEXT('\u2029')) ||
|
||||
(InChar == U32TEXT('\u205F')))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* CJK SYMBOLS AND PUNCTUATION, HIRAGANA
|
||||
* <U3000>;
|
||||
*/
|
||||
if (InChar == U32TEXT('\u3000')) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsBlank(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return NAMESPACE_STD::isblank(InChar, Loc);
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/* <U0009>;<U0020>; */
|
||||
return InChar == U8TEXT('\u0009') || InChar == U8TEXT('\u0020');
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
/* <U0009>;<U0020>;<U1680>;<U180E>;<U2000>..<U2006>;<U2008>..<U200A>;<U205F>;<U3000>; */
|
||||
return
|
||||
(InChar >= U16TEXT('\u2000') && InChar <= U16TEXT('\u2006')) ||
|
||||
(InChar == U16TEXT('\u0009') || InChar == U16TEXT('\u0020')) ||
|
||||
(InChar == U16TEXT('\u1680') || InChar == U16TEXT('\u180E')) ||
|
||||
(InChar == U16TEXT('\u2008') || InChar == U16TEXT('\u200A')) ||
|
||||
(InChar == U16TEXT('\u205F') || InChar == U16TEXT('\u3000'));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
/* <U0009>;<U0020>;<U1680>;<U180E>;<U2000>..<U2006>;<U2008>..<U200A>;<U205F>;<U3000>; */
|
||||
return
|
||||
(InChar >= U32TEXT('\u2000') && InChar <= U32TEXT('\u2006')) ||
|
||||
(InChar == U32TEXT('\u0009') || InChar == U32TEXT('\u0020')) ||
|
||||
(InChar == U32TEXT('\u1680') || InChar == U32TEXT('\u180E')) ||
|
||||
(InChar == U32TEXT('\u2008') || InChar == U32TEXT('\u200A')) ||
|
||||
(InChar == U32TEXT('\u205F') || InChar == U32TEXT('\u3000'));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsPrint(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return NAMESPACE_STD::isprint(InChar, Loc);
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* <U0020>..<U007E>;
|
||||
*/
|
||||
if (InChar >= U8TEXT('\u0020') && InChar <= U8TEXT('\u007E')) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsPrint() only supports basic latin block."));
|
||||
|
||||
if (InChar > U16TEXT('\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsPrint(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsPrint() only supports basic latin block."));
|
||||
|
||||
if (InChar > U32TEXT('\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsPrint(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsPunct(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return NAMESPACE_STD::ispunct(InChar, Loc);
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* <U0021>..<U002F>;<U003A>..<U0040>;<U005B>..<U0060>;<U007B>..<U007E>;
|
||||
*/
|
||||
if ((InChar >= U8TEXT('\u0021') && InChar <= U8TEXT('\u002F')) ||
|
||||
(InChar >= U8TEXT('\u003A') && InChar <= U8TEXT('\u0040')) ||
|
||||
(InChar >= U8TEXT('\u005B') && InChar <= U8TEXT('\u0060')) ||
|
||||
(InChar >= U8TEXT('\u007B') && InChar <= U8TEXT('\u007E')))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsPunct() only supports basic latin block."));
|
||||
|
||||
if (InChar > U16TEXT('\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsPunct(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsPunct() only supports basic latin block."));
|
||||
|
||||
if (InChar > U32TEXT('\u007F')) return false;
|
||||
|
||||
return TChar<u8char>::IsPunct(static_cast<u8char>(InChar));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr FCharType ToLower(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return static_cast<FCharType>(NAMESPACE_STD::tolower(InChar, Loc));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* (<U0041>,<U0061>);(<U0042>,<U0062>);(<U0043>,<U0063>);(<U0044>,<U0064>);
|
||||
* (<U0045>,<U0065>);(<U0046>,<U0066>);(<U0047>,<U0067>);(<U0048>,<U0068>);
|
||||
* (<U0049>,<U0069>);(<U004A>,<U006A>);(<U004B>,<U006B>);(<U004C>,<U006C>);
|
||||
* (<U004D>,<U006D>);(<U004E>,<U006E>);(<U004F>,<U006F>);(<U0050>,<U0070>);
|
||||
* (<U0051>,<U0071>);(<U0052>,<U0072>);(<U0053>,<U0073>);(<U0054>,<U0074>);
|
||||
* (<U0055>,<U0075>);(<U0056>,<U0076>);(<U0057>,<U0077>);(<U0058>,<U0078>);
|
||||
* (<U0059>,<U0079>);(<U005A>,<U007A>);
|
||||
*/
|
||||
if (InChar >= U8TEXT('\u0041') && InChar <= U8TEXT('\u005A')) return InChar + U8TEXT('\u0020');
|
||||
|
||||
return InChar;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::ToLower() only supports basic latin block."));
|
||||
|
||||
if (InChar > U16TEXT('\u007F')) return false;
|
||||
|
||||
return static_cast<u16char>(TChar<u8char>::ToLower(static_cast<u8char>(InChar)));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::ToLower() only supports basic latin block."));
|
||||
|
||||
if (InChar > U32TEXT('\u007F')) return false;
|
||||
|
||||
return static_cast<u16char>(TChar<u8char>::ToLower(static_cast<u8char>(InChar)));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return InChar;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr FCharType ToUpper(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
|
||||
{
|
||||
NAMESPACE_STD::locale Loc("");
|
||||
return static_cast<FCharType>(NAMESPACE_STD::toupper(InChar, Loc));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
/*
|
||||
* BASIC LATIN
|
||||
* (<U0061>,<U0041>);(<U0062>,<U0042>);(<U0063>,<U0043>);(<U0064>,<U0044>);/
|
||||
* (<U0065>,<U0045>);(<U0066>,<U0046>);(<U0067>,<U0047>);(<U0068>,<U0048>);/
|
||||
* (<U0069>,<U0049>);(<U006A>,<U004A>);(<U006B>,<U004B>);(<U006C>,<U004C>);/
|
||||
* (<U006D>,<U004D>);(<U006E>,<U004E>);(<U006F>,<U004F>);(<U0070>,<U0050>);/
|
||||
* (<U0071>,<U0051>);(<U0072>,<U0052>);(<U0073>,<U0053>);(<U0074>,<U0054>);/
|
||||
* (<U0075>,<U0055>);(<U0076>,<U0056>);(<U0077>,<U0057>);(<U0078>,<U0058>);/
|
||||
* (<U0079>,<U0059>);(<U007A>,<U005A>);
|
||||
*/
|
||||
if (InChar >= U8TEXT('\u0061') && InChar <= U8TEXT('\u007A')) return InChar - U8TEXT('\u0020');
|
||||
|
||||
return InChar;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u16char>)
|
||||
{
|
||||
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::ToUpper() only supports basic latin block."));
|
||||
|
||||
if (InChar > U16TEXT('\u007F')) return false;
|
||||
|
||||
return static_cast<u16char>(TChar<u8char>::ToUpper(static_cast<u8char>(InChar)));
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u32char>)
|
||||
{
|
||||
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::ToUpper() only supports basic latin block."));
|
||||
|
||||
if (InChar > U32TEXT('\u007F')) return false;
|
||||
|
||||
return static_cast<u16char>(TChar<u8char>::ToUpper(static_cast<u8char>(InChar)));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
|
||||
return InChar;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr unsigned ToDigit(FCharType InChar)
|
||||
{
|
||||
static_assert(TChar::IsASCII());
|
||||
|
||||
constexpr uint8 DigitFromChar[] =
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static_assert(sizeof(DigitFromChar) == 256);
|
||||
|
||||
if constexpr (sizeof(FCharType) > 1) if (InChar >> 8) return DigitFromChar[0];
|
||||
|
||||
return DigitFromChar[InChar];
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr unsigned ToDigit(FCharType InChar, bool bLowercase)
|
||||
{
|
||||
static_assert(TChar::IsASCII());
|
||||
|
||||
if (bLowercase)
|
||||
{
|
||||
constexpr uint8 DigitFromChar[] =
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static_assert(sizeof(DigitFromChar) == 256);
|
||||
|
||||
if constexpr (sizeof(FCharType) > 1) if (InChar >> 8) return DigitFromChar[0];
|
||||
|
||||
return DigitFromChar[InChar];
|
||||
}
|
||||
|
||||
constexpr uint8 DigitFromChar[] =
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static_assert(sizeof(DigitFromChar) == 256);
|
||||
|
||||
if constexpr (sizeof(FCharType) > 1) if (InChar >> 8) return DigitFromChar[0];
|
||||
|
||||
return DigitFromChar[InChar];
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr FCharType FromDigit(unsigned InDigit)
|
||||
{
|
||||
checkf(InDigit < 36, TEXT("Digit must be in the range [0, 35]."));
|
||||
|
||||
return LITERAL(FCharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit];
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr FCharType FromDigit(unsigned InDigit, bool bLowercase)
|
||||
{
|
||||
checkf(InDigit < 36, TEXT("Digit must be in the range [0, 35]."));
|
||||
|
||||
if (bLowercase) return LITERAL(FCharType, "0123456789abcdefghijklmnopqrstuvwxyz")[InDigit];
|
||||
|
||||
return LITERAL(FCharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using FChar = TChar<char>;
|
||||
using FWChar = TChar<wchar>;
|
||||
using FU8Char = TChar<u8char>;
|
||||
using FU16Char = TChar<u16char>;
|
||||
using FU32Char = TChar<u32char>;
|
||||
using FUnicodeChar = TChar<unicodechar>;
|
||||
|
||||
static_assert(FUnicodeChar::bIsFixedLength);
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
2816
Redcraft.Utility/Source/Public/Strings/Conversion.h.inl
Normal file
2816
Redcraft.Utility/Source/Public/Strings/Conversion.h.inl
Normal file
File diff suppressed because it is too large
Load Diff
1469
Redcraft.Utility/Source/Public/Strings/String.h
Normal file
1469
Redcraft.Utility/Source/Public/Strings/String.h
Normal file
File diff suppressed because it is too large
Load Diff
698
Redcraft.Utility/Source/Public/Strings/StringView.h
Normal file
698
Redcraft.Utility/Source/Public/Strings/StringView.h
Normal file
@ -0,0 +1,698 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/TypeHash.h"
|
||||
#include "Templates/Noncopyable.h"
|
||||
#include "Memory/Allocator.h"
|
||||
#include "Memory/MemoryOperator.h"
|
||||
#include "Containers/ArrayView.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Strings/Char.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cwchar>
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
template <CCharType T>
|
||||
class TStringView;
|
||||
|
||||
template <CCharType T, CAllocator<T> Allocator>
|
||||
class TString;
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <typename T> struct TIsTStringView : FFalse { };
|
||||
template <typename T> struct TIsTStringView<TStringView<T>> : FTrue { };
|
||||
|
||||
template <typename T>
|
||||
class TCStringFromTStringView final : FNoncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
FORCEINLINE TCStringFromTStringView(const T* InPtr, bool bInDelete)
|
||||
: Ptr(InPtr), bDelete(bInDelete)
|
||||
{ }
|
||||
|
||||
FORCEINLINE TCStringFromTStringView(TCStringFromTStringView&& InValue)
|
||||
: Ptr(InValue.Ptr), bDelete(Exchange(InValue.bDelete, false))
|
||||
{ }
|
||||
|
||||
FORCEINLINE ~TCStringFromTStringView()
|
||||
{
|
||||
if (bDelete) delete[] Ptr;
|
||||
}
|
||||
|
||||
FORCEINLINE TCStringFromTStringView& operator=(TCStringFromTStringView&& InValue)
|
||||
{
|
||||
if (bDelete) delete[] Ptr;
|
||||
|
||||
Ptr = InValue.Ptr;
|
||||
|
||||
bDelete = Exchange(InValue.bDelete, false);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE operator const T*() const { return Ptr; }
|
||||
|
||||
private:
|
||||
|
||||
const T* Ptr;
|
||||
bool bDelete;
|
||||
|
||||
};
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
template <typename T> concept CTStringView = NAMESPACE_PRIVATE::TIsTStringView<TRemoveCV<T>>::Value;
|
||||
|
||||
/**
|
||||
* The class template TStringView describes an object that can refer to a constant contiguous sequence of char-like objects
|
||||
* with the first element of the sequence at position zero. Provides a set of convenient string processing functions.
|
||||
*/
|
||||
template <CCharType T>
|
||||
class TStringView : public TArrayView<const T>
|
||||
{
|
||||
private:
|
||||
|
||||
using FSuper = TArrayView<const T>;
|
||||
|
||||
public:
|
||||
|
||||
using FElementType = T;
|
||||
|
||||
using FReference = typename FSuper::FReference;
|
||||
|
||||
using FIterator = typename FSuper:: FIterator;
|
||||
using FReverseIterator = typename FSuper::FReverseIterator;
|
||||
|
||||
static_assert(CContiguousIterator<FIterator>);
|
||||
|
||||
/** Constructs an empty string view. */
|
||||
FORCEINLINE constexpr TStringView() = default;
|
||||
|
||||
/** Constructs a string view that is a view over the range ['InFirst', 'InFirst' + 'Count'). */
|
||||
template <CContiguousIterator I> requires (CConvertibleTo<TIteratorReference<I>, T> && CSameAs<TRemoveCVRef<TIteratorReference<I>>, TRemoveCVRef<T>>)
|
||||
FORCEINLINE constexpr TStringView(I InFirst, size_t InCount) : FSuper(InFirst, InCount) { }
|
||||
|
||||
/** Constructs a string view that is a view over the range ['InFirst', 'InLast'). */
|
||||
template <CContiguousIterator I, CSizedSentinelFor<I> S> requires (CConvertibleTo<TIteratorReference<I>, T> && CSameAs<TRemoveCVRef<TIteratorReference<I>>, TRemoveCVRef<T>>)
|
||||
FORCEINLINE constexpr TStringView(I InFirst, S InLast) : FSuper(InFirst, InLast) { }
|
||||
|
||||
/** Constructs a string view that is a view over the string 'InString'. */
|
||||
template <typename Allocator>
|
||||
FORCEINLINE constexpr TStringView(const TString<FElementType, Allocator>& InString);
|
||||
|
||||
/** Constructs a string view that is a view over the range ['InPtr', 'InPtr' + 'Count'). */
|
||||
FORCEINLINE constexpr TStringView(const FElementType* InPtr, size_t Count) : FSuper(InPtr, Count)
|
||||
{
|
||||
checkf(InPtr != nullptr, TEXT("TStringView cannot be initialized by nullptr. Please check the pointer."));
|
||||
}
|
||||
|
||||
FORCEINLINE constexpr TStringView(nullptr_t, size_t) = delete;
|
||||
|
||||
/** Constructs a string view that is a view over the range ['InPtr', '\0'). */
|
||||
FORCEINLINE constexpr TStringView(const FElementType* InPtr)
|
||||
{
|
||||
checkf(InPtr != nullptr, TEXT("TStringView cannot be initialized by nullptr. Please check the pointer."));
|
||||
|
||||
size_t Length = 0;
|
||||
|
||||
if constexpr (CSameAs<FElementType, char>)
|
||||
{
|
||||
Length = NAMESPACE_STD::strlen(InPtr);
|
||||
}
|
||||
else if constexpr (CSameAs<FElementType, wchar>)
|
||||
{
|
||||
Length = NAMESPACE_STD::wcslen(InPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (InPtr[Length] != LITERAL(FElementType, '\0')) ++Length;
|
||||
}
|
||||
|
||||
*this = TStringView(InPtr, Length);
|
||||
}
|
||||
|
||||
FORCEINLINE constexpr TStringView(nullptr_t) = delete;
|
||||
|
||||
/** Defaulted copy constructor copies the size and data pointer. */
|
||||
FORCEINLINE constexpr TStringView(const TStringView&) = default;
|
||||
|
||||
/** Assigns other to *this. This defaulted assignment operator performs a shallow copy of the data pointer and the size. */
|
||||
FORCEINLINE constexpr TStringView& operator=(const TStringView&) noexcept = default;
|
||||
|
||||
/** Compares the contents of two string views. */
|
||||
NODISCARD friend constexpr bool operator==(TStringView LHS, TStringView RHS) { return static_cast<FSuper>(LHS) == static_cast<FSuper>(RHS); }
|
||||
|
||||
/** Compares the contents of a string view and a character. */
|
||||
NODISCARD friend constexpr bool operator==(TStringView LHS, FElementType RHS) { return LHS == TStringView(&RHS, 1); }
|
||||
NODISCARD friend constexpr bool operator==(FElementType LHS, TStringView RHS) { return TStringView(&LHS, 1) == RHS; }
|
||||
|
||||
/** Compares the contents of two string views. */
|
||||
NODISCARD friend constexpr auto operator<=>(TStringView LHS, TStringView RHS) { return static_cast<FSuper>(LHS) <=> static_cast<FSuper>(RHS); }
|
||||
|
||||
/** Compares the contents of a string view and a character. */
|
||||
NODISCARD friend constexpr auto operator<=>(TStringView LHS, FElementType RHS) { return LHS <=> TStringView(&RHS, 1); }
|
||||
NODISCARD friend constexpr auto operator<=>(FElementType LHS, TStringView RHS) { return TStringView(&LHS, 1) <=> RHS; }
|
||||
|
||||
public:
|
||||
|
||||
/** Shrinks the view by moving its start forward. */
|
||||
FORCEINLINE constexpr TStringView& RemovePrefix(size_t Count)
|
||||
{
|
||||
checkf(Count <= this->Num(), TEXT("Illegal subview range. Please check Count."));
|
||||
|
||||
*this = Substr(Count);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Shrinks the view by moving its end backward. */
|
||||
FORCEINLINE constexpr TStringView& RemoveSuffix(size_t Count)
|
||||
{
|
||||
checkf(Count <= this->Num(), TEXT("Illegal subview range. Please check 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([](FElementType Char) { return !TChar<FElementType>::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([](FElementType Char) { return !TChar<FElementType>::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(FElementType, '\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. */
|
||||
FORCEINLINE constexpr size_t Copy(FElementType* Dest, size_t Count = DynamicExtent, size_t Offset = 0) const
|
||||
{
|
||||
checkf(Dest != nullptr, TEXT("Illegal destination buffer. Please check the pointer."));
|
||||
|
||||
checkf(Offset <= this->Num() && (Count == DynamicExtent || Offset + Count <= this->Num()), TEXT("Illegal subview range. Please check Offset and Count."));
|
||||
|
||||
if (Count == DynamicExtent)
|
||||
{
|
||||
Count = this->Num() - Offset;
|
||||
}
|
||||
|
||||
Memory::CopyAssign(Dest, this->GetData() + Offset, Count);
|
||||
|
||||
return Count;
|
||||
}
|
||||
|
||||
FORCEINLINE constexpr size_t Copy(nullptr_t, size_t Count = DynamicExtent, size_t Offset = 0) const = delete;
|
||||
|
||||
/** Obtains an array view that is a view over the first 'Count' elements of this array view. */
|
||||
NODISCARD FORCEINLINE constexpr TStringView First(size_t Count) const
|
||||
{
|
||||
checkf(Count <= this->Num(), TEXT("Illegal subview range. Please check Count."));
|
||||
|
||||
return Substr(0, Count);
|
||||
}
|
||||
|
||||
/** Obtains an array view that is a view over the last 'Count' elements of this array view. */
|
||||
NODISCARD FORCEINLINE constexpr TStringView Last(size_t Count) const
|
||||
{
|
||||
checkf(Count <= this->Num(), TEXT("Illegal subview range. Please check Count."));
|
||||
|
||||
return Substr(this->Num() - Count);
|
||||
}
|
||||
|
||||
/** Obtains a string view that is a view over the 'Count' elements of this string view starting at 'Offset'. */
|
||||
NODISCARD FORCEINLINE constexpr TStringView Substr(size_t Offset, size_t Count = DynamicExtent) const
|
||||
{
|
||||
checkf(Offset <= this->Num() && (Count == DynamicExtent || Offset + Count <= this->Num()), TEXT("Illegal subview range. Please check Offset and Count."));
|
||||
|
||||
FSuper Temp = this->Subview(Offset, Count);
|
||||
|
||||
return TStringView(Temp.GetData(), Temp.Num());
|
||||
}
|
||||
|
||||
/** @return true if the string view starts with the given prefix, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr bool StartsWith(TStringView Prefix) const
|
||||
{
|
||||
return this->Num() >= Prefix.Num() && Substr(0, Prefix.Num()) == Prefix;
|
||||
}
|
||||
|
||||
/** @return true if the string view starts with the given prefix, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr bool StartsWith(FElementType Prefix) const
|
||||
{
|
||||
return this->Num() >= 1 && this->Front() == Prefix;
|
||||
}
|
||||
|
||||
/** @return true if the string view ends with the given suffix, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr bool EndsWith(TStringView Suffix) const
|
||||
{
|
||||
return this->Num() >= Suffix.Num() && Substr(this->Num() - Suffix.Num(), Suffix.Num()) == Suffix;
|
||||
}
|
||||
|
||||
/** @return true if the string view ends with the given suffix, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr bool EndsWith(FElementType Suffix) const
|
||||
{
|
||||
return this->Num() >= 1 && this->Back() == Suffix;
|
||||
}
|
||||
|
||||
/** @return true if the string view contains the given substring, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr bool Contains(TStringView View) const
|
||||
{
|
||||
return Find(View) != INDEX_NONE;
|
||||
}
|
||||
|
||||
/** @return true if the string view contains the given character, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr bool Contains(FElementType Char) const
|
||||
{
|
||||
return Find(Char) != INDEX_NONE;
|
||||
}
|
||||
|
||||
/** @return true if the string view contains character that satisfy the given predicate, false otherwise. */
|
||||
template <CPredicate<FElementType> F>
|
||||
NODISCARD FORCEINLINE constexpr bool Contains(F&& InPredicate) const
|
||||
{
|
||||
return Find(Forward<F>(InPredicate)) != INDEX_NONE;
|
||||
}
|
||||
|
||||
/** @return The index of the first occurrence of the given substring, or INDEX_NONE if not found. */
|
||||
NODISCARD constexpr size_t Find(TStringView View, size_t Index = 0) const
|
||||
{
|
||||
if (Index >= this->Num()) return INDEX_NONE;
|
||||
|
||||
if (View.Num() > this->Num()) return INDEX_NONE;
|
||||
|
||||
if (View.Num() == 0) return Index;
|
||||
|
||||
for (; Index != this->Num() - View.Num() + 1; ++Index)
|
||||
{
|
||||
if (Substr(Index).StartsWith(View))
|
||||
{
|
||||
return Index;
|
||||
}
|
||||
}
|
||||
|
||||
return INDEX_NONE;
|
||||
}
|
||||
|
||||
/** @return The index of the first occurrence of the given character, or INDEX_NONE if not found. */
|
||||
NODISCARD constexpr size_t Find(FElementType Char, size_t Index = 0) const
|
||||
{
|
||||
if (Index >= this->Num()) return INDEX_NONE;
|
||||
|
||||
for (; Index != this->Num(); ++Index)
|
||||
{
|
||||
if ((*this)[Index] == Char)
|
||||
{
|
||||
return Index;
|
||||
}
|
||||
}
|
||||
|
||||
return INDEX_NONE;
|
||||
}
|
||||
|
||||
/** @return The index of the first occurrence of the character that satisfy the given predicate, or INDEX_NONE if not found. */
|
||||
template <CPredicate<FElementType> F>
|
||||
NODISCARD constexpr size_t Find(F&& InPredicate, size_t Index = 0) const
|
||||
{
|
||||
if (Index >= this->Num()) return INDEX_NONE;
|
||||
|
||||
for (; Index != this->Num(); ++Index)
|
||||
{
|
||||
if (InvokeResult<bool>(Forward<F>(InPredicate), (*this)[Index]))
|
||||
{
|
||||
return Index;
|
||||
}
|
||||
}
|
||||
|
||||
return INDEX_NONE;
|
||||
}
|
||||
|
||||
/** @return The index of the last occurrence of the given substring, or INDEX_NONE if not found. */
|
||||
NODISCARD constexpr size_t RFind(TStringView View, size_t Index = INDEX_NONE) const
|
||||
{
|
||||
if (Index != INDEX_NONE && Index >= this->Num()) return INDEX_NONE;
|
||||
|
||||
if (View.Num() > this->Num()) return INDEX_NONE;
|
||||
|
||||
if (Index == INDEX_NONE) Index = this->Num();
|
||||
|
||||
if (View.Num() == 0) return Index;
|
||||
|
||||
for (; Index != View.Num() - 1; --Index)
|
||||
{
|
||||
if (Substr(0, Index).EndsWith(View))
|
||||
{
|
||||
return Index - View.Num();
|
||||
}
|
||||
}
|
||||
|
||||
return INDEX_NONE;
|
||||
}
|
||||
|
||||
/** @return The index of the last occurrence of the given character, or INDEX_NONE if not found. */
|
||||
NODISCARD constexpr size_t RFind(FElementType Char, size_t Index = INDEX_NONE) const
|
||||
{
|
||||
if (Index != INDEX_NONE && Index >= this->Num()) return INDEX_NONE;
|
||||
|
||||
if (Index == INDEX_NONE) Index = this->Num();
|
||||
|
||||
for (; Index != 0; --Index)
|
||||
{
|
||||
if ((*this)[Index - 1] == Char)
|
||||
{
|
||||
return Index - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return INDEX_NONE;
|
||||
}
|
||||
|
||||
/** @return The index of the last occurrence of the character that satisfy the given predicate, or INDEX_NONE if not found. */
|
||||
template <CPredicate<FElementType> F>
|
||||
NODISCARD constexpr size_t RFind(F&& InPredicate, size_t Index = INDEX_NONE) const
|
||||
{
|
||||
if (Index != INDEX_NONE && Index >= this->Num()) return INDEX_NONE;
|
||||
|
||||
if (Index == INDEX_NONE) Index = this->Num();
|
||||
|
||||
for (; Index != 0; --Index)
|
||||
{
|
||||
if (InvokeResult<bool>(Forward<F>(InPredicate), (*this)[Index - 1]))
|
||||
{
|
||||
return Index - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return INDEX_NONE;
|
||||
}
|
||||
|
||||
/** @return The index of the first occurrence of the character contained in the given view, or INDEX_NONE if not found. */
|
||||
NODISCARD FORCEINLINE constexpr size_t FindFirstOf(TStringView View, size_t Index = 0) const
|
||||
{
|
||||
return Find([View](FElementType Char) { return View.Contains(Char); }, Index);
|
||||
}
|
||||
|
||||
/** @return The index of the first occurrence of the given character, or INDEX_NONE if not found. */
|
||||
NODISCARD FORCEINLINE constexpr size_t FindFirstOf(FElementType Char, size_t Index = 0) const
|
||||
{
|
||||
return Find(Char, Index);
|
||||
}
|
||||
|
||||
/** @return The index of the last occurrence of the character contained in the given view, or INDEX_NONE if not found. */
|
||||
NODISCARD FORCEINLINE constexpr size_t FindLastOf(TStringView View, size_t Index = INDEX_NONE) const
|
||||
{
|
||||
return RFind([View](FElementType Char) { return View.Contains(Char); }, Index);
|
||||
}
|
||||
|
||||
/** @return The index of the last occurrence of the given character, or INDEX_NONE if not found. */
|
||||
NODISCARD FORCEINLINE constexpr size_t FindLastOf(FElementType Char, size_t Index = INDEX_NONE) const
|
||||
{
|
||||
return RFind(Char, Index);
|
||||
}
|
||||
|
||||
/** @return The index of the first absence of the character contained in the given view, or INDEX_NONE if not found. */
|
||||
NODISCARD FORCEINLINE constexpr size_t FindFirstNotOf(TStringView View, size_t Index = 0) const
|
||||
{
|
||||
return Find([View](FElementType Char) { return !View.Contains(Char); }, Index);
|
||||
}
|
||||
|
||||
/** @return The index of the first absence of the given character, or INDEX_NONE if not found. */
|
||||
NODISCARD FORCEINLINE constexpr size_t FindFirstNotOf(FElementType Char, size_t Index = 0) const
|
||||
{
|
||||
return Find([Char](FElementType C) { return C != Char; }, Index);
|
||||
}
|
||||
|
||||
/** @return The index of the last absence of the character contained in the given view, or INDEX_NONE if not found. */
|
||||
NODISCARD FORCEINLINE constexpr size_t FindLastNotOf(TStringView View, size_t Index = INDEX_NONE) const
|
||||
{
|
||||
return RFind([View](FElementType Char) { return !View.Contains(Char); }, Index);
|
||||
}
|
||||
|
||||
/** @return The index of the last absence of the given character, or INDEX_NONE if not found. */
|
||||
NODISCARD FORCEINLINE constexpr size_t FindLastNotOf(FElementType Char, size_t Index = INDEX_NONE) const
|
||||
{
|
||||
return RFind([Char](FElementType C) { return C != Char; }, Index);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/** @return The non-modifiable standard C character string version of the string view. */
|
||||
NODISCARD FORCEINLINE auto operator*() const
|
||||
{
|
||||
if (this->Back() == LITERAL(FElementType, '\0') || Contains(LITERAL(FElementType, '\0')))
|
||||
{
|
||||
return NAMESPACE_PRIVATE::TCStringFromTStringView<FElementType>(this->GetData(), false);
|
||||
}
|
||||
|
||||
FElementType* Buffer = new FElementType[this->Num() + 1];
|
||||
|
||||
Copy(Buffer);
|
||||
|
||||
Buffer[this->Num()] = LITERAL(FElementType, '\0');
|
||||
|
||||
return NAMESPACE_PRIVATE::TCStringFromTStringView<FElementType>(Buffer, true);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/** @return true if the string only contains valid characters, false otherwise. */
|
||||
NODISCARD constexpr bool IsValid() const
|
||||
{
|
||||
for (FElementType Char : *this)
|
||||
{
|
||||
if (!TChar<FElementType>::IsValid(Char)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return true if the string only contains ASCII characters, false otherwise. */
|
||||
NODISCARD constexpr bool IsASCII() const
|
||||
{
|
||||
for (FElementType Char : *this)
|
||||
{
|
||||
if (!TChar<FElementType>::IsASCII(Char)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return true if the string can be fully represented as a boolean value, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr bool IsBoolean() const
|
||||
{
|
||||
TStringView View = *this;
|
||||
|
||||
Ignore = View.ToBoolAndTrim();
|
||||
|
||||
return View.IsEmpty();
|
||||
}
|
||||
|
||||
/** @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(FElementType, '-')))
|
||||
{
|
||||
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(FElementType, '-')))
|
||||
{
|
||||
if (bSigned) View.RemovePrefix(1);
|
||||
else return false;
|
||||
}
|
||||
|
||||
Ignore = View.ToFloatAndTrim(bFixed, bScientific);
|
||||
|
||||
return View.IsEmpty();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Converts a string into a boolean value.
|
||||
*
|
||||
* - "True" and non-zero integers become true.
|
||||
* - "False" and unparsable values become false.
|
||||
*
|
||||
* @return The boolean value.
|
||||
*/
|
||||
NODISCARD constexpr bool ToBool() const
|
||||
{
|
||||
return TStringView(*this).ToBoolAndTrim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
return TStringView(*this).ToIntAndTrim<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 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:
|
||||
|
||||
/**
|
||||
* Parse a string using a format string to objects.
|
||||
*
|
||||
* @param Fmt - The format string.
|
||||
* @param Args - The objects to parse.
|
||||
*
|
||||
* @return The number of objects successfully parsed.
|
||||
*/
|
||||
template <typename... Ts>
|
||||
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:
|
||||
|
||||
/** Overloads the GetTypeHash algorithm for TStringView. */
|
||||
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(TStringView A) { return GetTypeHash(static_cast<FSuper>(A)); }
|
||||
|
||||
};
|
||||
|
||||
template <CPointer I>
|
||||
TStringView(I) -> TStringView<TIteratorElement<I>>;
|
||||
|
||||
template <typename I, typename S>
|
||||
TStringView(I, S) -> TStringView<TIteratorElement<I>>;
|
||||
|
||||
template<typename T, typename Allocator>
|
||||
TStringView(TString<T, Allocator>) -> TStringView<T>;
|
||||
|
||||
using FStringView = TStringView<char>;
|
||||
using FWStringView = TStringView<wchar>;
|
||||
using FU8StringView = TStringView<u8char>;
|
||||
using FU16StringView = TStringView<u16char>;
|
||||
using FU32StringView = TStringView<u32char>;
|
||||
using FUnicodeStringView = TStringView<unicodechar>;
|
||||
|
||||
// ReSharper disable CppInconsistentNaming
|
||||
|
||||
#define TEXT_VIEW(X) TStringView(TEXT(X))
|
||||
#define WTEXT_VIEW(X) TStringView(WTEXT(X))
|
||||
#define U8TEXT_VIEW(X) TStringView(U8TEXT(X))
|
||||
#define U16TEXT_VIEW(X) TStringView(U16TEXT(X))
|
||||
#define U32TEXT_VIEW(X) TStringView(U32TEXT(X))
|
||||
#define UNICODETEXT_VIEW(X) TStringView(UNICODETEXT(X))
|
||||
|
||||
#define LITERAL_VIEW(T, X) TStringView(LITERAL(T, X))
|
||||
|
||||
// ReSharper restore CppInconsistentNaming
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
Reference in New Issue
Block a user