From 5210db43b36bd74f4a4fd6c356715d8b2d3459e8 Mon Sep 17 00:00:00 2001 From: Redstone1024 <2824517378@qq.com> Date: Tue, 17 Sep 2024 18:06:02 +0800 Subject: [PATCH] feat(string): add single character utility and the corresponding testing --- .../Source/Private/Testing/StringTesting.cpp | 235 +++++++ .../Public/Miscellaneous/CoreMiscDefines.h | 1 - .../Source/Public/Miscellaneous/Platform.h | 36 +- Redcraft.Utility/Source/Public/String/Char.h | 613 ++++++++++++++++++ .../Source/Public/Testing/StringTesting.h | 18 + 5 files changed, 881 insertions(+), 22 deletions(-) create mode 100644 Redcraft.Utility/Source/Private/Testing/StringTesting.cpp create mode 100644 Redcraft.Utility/Source/Public/String/Char.h create mode 100644 Redcraft.Utility/Source/Public/Testing/StringTesting.h diff --git a/Redcraft.Utility/Source/Private/Testing/StringTesting.cpp b/Redcraft.Utility/Source/Private/Testing/StringTesting.cpp new file mode 100644 index 0000000..a30fb1c --- /dev/null +++ b/Redcraft.Utility/Source/Private/Testing/StringTesting.cpp @@ -0,0 +1,235 @@ +#include "Testing/StringTesting.h" + +#include "String/Char.h" +#include "Miscellaneous/AssertionMacros.h" + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +NAMESPACE_BEGIN(Testing) + +void TestString() +{ + TestChar(); +} + +void TestChar() +{ + { + always_check(!CCharType); + always_check(CCharType); + always_check(CCharType); + always_check(CCharType); + always_check(CCharType); + always_check(CCharType); + } + + { + always_check(FChar::IsAlnum(TEXT('0'))); + always_check(FChar::IsAlpha(TEXT('A'))); + always_check(FChar::IsLower(TEXT('a'))); + always_check(FChar::IsUpper(TEXT('A'))); + always_check(FChar::IsDigit(TEXT('0'))); + always_check(FChar::IsCntrl(TEXT('\n'))); + always_check(FChar::IsGraph(TEXT('!'))); + always_check(FChar::IsSpace(TEXT('\t'))); + always_check(FChar::IsBlank(TEXT(' '))); + always_check(FChar::IsPrint(TEXT('#'))); + always_check(FChar::IsPunct(TEXT('['))); + } + + { + always_check(FWChar::IsAlnum(WTEXT('0'))); + always_check(FWChar::IsAlpha(WTEXT('A'))); + always_check(FWChar::IsLower(WTEXT('a'))); + always_check(FWChar::IsUpper(WTEXT('A'))); + always_check(FWChar::IsDigit(WTEXT('0'))); + always_check(FWChar::IsCntrl(WTEXT('\n'))); + always_check(FWChar::IsGraph(WTEXT('!'))); + always_check(FWChar::IsSpace(WTEXT('\t'))); + always_check(FWChar::IsBlank(WTEXT(' '))); + always_check(FWChar::IsPrint(WTEXT('#'))); + always_check(FWChar::IsPunct(WTEXT('['))); + } + + { + always_check(FU8Char::IsAlnum(U8TEXT('0'))); + always_check(FU8Char::IsAlpha(U8TEXT('A'))); + always_check(FU8Char::IsLower(U8TEXT('a'))); + always_check(FU8Char::IsUpper(U8TEXT('A'))); + always_check(FU8Char::IsDigit(U8TEXT('0'))); + always_check(FU8Char::IsCntrl(U8TEXT('\n'))); + always_check(FU8Char::IsGraph(U8TEXT('!'))); + always_check(FU8Char::IsSpace(U8TEXT('\t'))); + always_check(FU8Char::IsBlank(U8TEXT(' '))); + always_check(FU8Char::IsPrint(U8TEXT('#'))); + always_check(FU8Char::IsPunct(U8TEXT('['))); + } + + { + //always_check(FU16Char::IsAlnum(U16TEXT('0'))); + //always_check(FU16Char::IsAlpha(U16TEXT('A'))); + //always_check(FU16Char::IsLower(U16TEXT('a'))); + //always_check(FU16Char::IsUpper(U16TEXT('A'))); + always_check(FU16Char::IsDigit(U16TEXT('0'))); + always_check(FU16Char::IsCntrl(U16TEXT('\n'))); + //always_check(FU16Char::IsGraph(U16TEXT('!'))); + always_check(FU16Char::IsSpace(U16TEXT('\t'))); + always_check(FU16Char::IsBlank(U16TEXT(' '))); + //always_check(FU16Char::IsPrint(U16TEXT('#'))); + //always_check(FU16Char::IsPunct(U16TEXT('['))); + } + + { + //always_check(FU32Char::IsAlnum(U32TEXT('0'))); + //always_check(FU32Char::IsAlpha(U32TEXT('A'))); + //always_check(FU32Char::IsLower(U32TEXT('a'))); + //always_check(FU32Char::IsUpper(U32TEXT('A'))); + always_check(FU32Char::IsDigit(U32TEXT('0'))); + always_check(FU32Char::IsCntrl(U32TEXT('\n'))); + //always_check(FU32Char::IsGraph(U32TEXT('!'))); + always_check(FU32Char::IsSpace(U32TEXT('\t'))); + always_check(FU32Char::IsBlank(U32TEXT(' '))); + //always_check(FU32Char::IsPrint(U32TEXT('#'))); + //always_check(FU32Char::IsPunct(U32TEXT('['))); + } + + { + always_check(!FChar::IsAlnum(TEXT('$'))); + always_check(!FChar::IsAlpha(TEXT('0'))); + always_check(!FChar::IsLower(TEXT('A'))); + always_check(!FChar::IsUpper(TEXT('a'))); + always_check(!FChar::IsDigit(TEXT('I'))); + always_check(!FChar::IsCntrl(TEXT('_'))); + always_check(!FChar::IsGraph(TEXT(' '))); + always_check(!FChar::IsSpace(TEXT('='))); + always_check(!FChar::IsBlank(TEXT('\r'))); + always_check(!FChar::IsPrint(TEXT('\n'))); + always_check(!FChar::IsPunct(TEXT('H'))); + } + + { + always_check(!FWChar::IsAlnum(WTEXT('$'))); + always_check(!FWChar::IsAlpha(WTEXT('0'))); + always_check(!FWChar::IsLower(WTEXT('A'))); + always_check(!FWChar::IsUpper(WTEXT('a'))); + always_check(!FWChar::IsDigit(WTEXT('I'))); + always_check(!FWChar::IsCntrl(WTEXT('_'))); + always_check(!FWChar::IsGraph(WTEXT(' '))); + always_check(!FWChar::IsSpace(WTEXT('='))); + always_check(!FWChar::IsBlank(WTEXT('\r'))); + always_check(!FWChar::IsPrint(WTEXT('\n'))); + always_check(!FWChar::IsPunct(WTEXT('H'))); + } + + { + always_check(!FU8Char::IsAlnum(U8TEXT('$'))); + always_check(!FU8Char::IsAlpha(U8TEXT('0'))); + always_check(!FU8Char::IsLower(U8TEXT('A'))); + always_check(!FU8Char::IsUpper(U8TEXT('a'))); + always_check(!FU8Char::IsDigit(U8TEXT('I'))); + always_check(!FU8Char::IsCntrl(U8TEXT('_'))); + always_check(!FU8Char::IsGraph(U8TEXT(' '))); + always_check(!FU8Char::IsSpace(U8TEXT('='))); + always_check(!FU8Char::IsBlank(U8TEXT('\r'))); + always_check(!FU8Char::IsPrint(U8TEXT('\n'))); + always_check(!FU8Char::IsPunct(U8TEXT('H'))); + } + + { + //always_check(!FU16Char::IsAlnum(U16TEXT('$'))); + //always_check(!FU16Char::IsAlpha(U16TEXT('0'))); + //always_check(!FU16Char::IsLower(U16TEXT('A'))); + //always_check(!FU16Char::IsUpper(U16TEXT('a'))); + always_check(!FU16Char::IsDigit(U16TEXT('I'))); + always_check(!FU16Char::IsCntrl(U16TEXT('_'))); + //always_check(!FU16Char::IsGraph(U16TEXT(' '))); + always_check(!FU16Char::IsSpace(U16TEXT('='))); + always_check(!FU16Char::IsBlank(U16TEXT('\r'))); + //always_check(!FU16Char::IsPrint(U16TEXT('\n'))); + //always_check(!FU16Char::IsPunct(U16TEXT('H'))); + } + + { + //always_check(!FU32Char::IsAlnum(U32TEXT('$'))); + //always_check(!FU32Char::IsAlpha(U32TEXT('0'))); + //always_check(!FU32Char::IsLower(U32TEXT('A'))); + //always_check(!FU32Char::IsUpper(U32TEXT('a'))); + always_check(!FU32Char::IsDigit(U32TEXT('I'))); + always_check(!FU32Char::IsCntrl(U32TEXT('_'))); + //always_check(!FU32Char::IsGraph(U32TEXT(' '))); + always_check(!FU32Char::IsSpace(U32TEXT('='))); + always_check(!FU32Char::IsBlank(U32TEXT('\r'))); + //always_check(!FU32Char::IsPrint(U32TEXT('\n'))); + //always_check(!FU32Char::IsPunct(U32TEXT('H'))); + } + + { + always_check( FChar::IsDigit(TEXT('F'), 16)); + always_check(!FChar::IsDigit(TEXT('G'), 16)); + always_check( FWChar::IsDigit(WTEXT('F'), 16)); + always_check(!FWChar::IsDigit(WTEXT('G'), 16)); + always_check( FU8Char::IsDigit(U8TEXT('F'), 16)); + always_check(!FU8Char::IsDigit(U8TEXT('G'), 16)); + always_check( FU16Char::IsDigit(U16TEXT('F'), 16)); + always_check(!FU16Char::IsDigit(U16TEXT('G'), 16)); + always_check( FU32Char::IsDigit(U32TEXT('F'), 16)); + always_check(!FU32Char::IsDigit(U32TEXT('G'), 16)); + } + + { + always_check(FChar::ToLower(TEXT('i')) == TEXT('i')); + always_check(FChar::ToUpper(TEXT('l')) == TEXT('L')); + always_check(FWChar::ToUpper(WTEXT('l')) == WTEXT('L')); + always_check(FWChar::ToLower(WTEXT('i')) == WTEXT('i')); + always_check(FU8Char::ToLower(U8TEXT('i')) == U8TEXT('i')); + always_check(FU8Char::ToUpper(U8TEXT('l')) == U8TEXT('L')); + //always_check(FU16Char::ToLower(U16TEXT('i')) == U16TEXT('i')); + //always_check(FU16Char::ToUpper(U16TEXT('l')) == U16TEXT('L')); + //always_check(FU32Char::ToLower(U32TEXT('i')) == U32TEXT('i')); + //always_check(FU32Char::ToUpper(U32TEXT('l')) == U32TEXT('L')); + } + + { + always_check(0x0 == FChar::ToDigit(TEXT('0'))); + always_check(0xF == FChar::ToDigit(TEXT('f'))); + always_check(0xF == FChar::ToDigit(TEXT('F'))); + always_check(0x0 == FWChar::ToDigit(WTEXT('0'))); + always_check(0xF == FWChar::ToDigit(WTEXT('f'))); + always_check(0xF == FWChar::ToDigit(WTEXT('F'))); + always_check(0x0 == FU8Char::ToDigit(U8TEXT('0'))); + always_check(0xF == FU8Char::ToDigit(U8TEXT('f'))); + always_check(0xF == FU8Char::ToDigit(U8TEXT('F'))); + always_check(0x0 == FU16Char::ToDigit(U16TEXT('0'))); + always_check(0xF == FU16Char::ToDigit(U16TEXT('f'))); + always_check(0xF == FU16Char::ToDigit(U16TEXT('F'))); + always_check(0x0 == FU16Char::ToDigit(U16TEXT('0'))); + always_check(0xF == FU16Char::ToDigit(U16TEXT('f'))); + always_check(0xF == FU16Char::ToDigit(U16TEXT('F'))); + } + + { + always_check(TEXT('0') == FChar::FromDigit(0x0)); + always_check(TEXT('f') != FChar::FromDigit(0xF)); + always_check(TEXT('F') == FChar::FromDigit(0xF)); + always_check(WTEXT('0') == FWChar::FromDigit(0x0)); + always_check(WTEXT('f') != FWChar::FromDigit(0xF)); + always_check(WTEXT('F') == FWChar::FromDigit(0xF)); + always_check(U8TEXT('0') == FU8Char::FromDigit(0x0)); + always_check(U8TEXT('f') != FU8Char::FromDigit(0xF)); + always_check(U8TEXT('F') == FU8Char::FromDigit(0xF)); + always_check(U16TEXT('0') == FU16Char::FromDigit(0x0)); + always_check(U16TEXT('f') != FU16Char::FromDigit(0xF)); + always_check(U16TEXT('F') == FU16Char::FromDigit(0xF)); + always_check(U16TEXT('0') == FU16Char::FromDigit(0x0)); + always_check(U16TEXT('f') != FU16Char::FromDigit(0xF)); + always_check(U16TEXT('F') == FU16Char::FromDigit(0xF)); + } +} + +NAMESPACE_END(Testing) + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/CoreMiscDefines.h b/Redcraft.Utility/Source/Public/Miscellaneous/CoreMiscDefines.h index 41c38a8..b69030c 100644 --- a/Redcraft.Utility/Source/Public/Miscellaneous/CoreMiscDefines.h +++ b/Redcraft.Utility/Source/Public/Miscellaneous/CoreMiscDefines.h @@ -20,7 +20,6 @@ NAMESPACE_MODULE_BEGIN(Utility) #define NO_UNIQUE_ADDRESS [[no_unique_address]] constexpr size_t INDEX_NONE = -1; -constexpr charw UNICODE_BOM = 0xfeff; struct FForceInit { explicit FForceInit() = default; }; struct FNoInit { explicit FNoInit() = default; }; diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/Platform.h b/Redcraft.Utility/Source/Public/Miscellaneous/Platform.h index a4859d8..6d7387f 100644 --- a/Redcraft.Utility/Source/Public/Miscellaneous/Platform.h +++ b/Redcraft.Utility/Source/Public/Miscellaneous/Platform.h @@ -159,15 +159,6 @@ using int64 = NAMESPACE_STD::int64_t; using float32 = float; using float64 = double; -// Character types - -using chara = char; -using charw = wchar_t; -using chart = charw; -using char8 = char8_t; -using char16 = char16_t; -using char32 = char32_t; - // Pointer types using uintptr = NAMESPACE_STD::uintptr_t; @@ -181,20 +172,23 @@ using ssize_t = intptr_t; using null_t = decltype(NULL); using nullptr_t = NAMESPACE_STD::nullptr_t; -#if PLATFORM_LINUX -# define PLATFORM_TCHAR_IS_CHAR16 1 -#else -# define PLATFORM_TCHAR_IS_CHAR16 0 -#endif - // Define the TEXT macro -#if PLATFORM_TCHAR_IS_CHAR16 -# define TEXT_PASTE(x) u ## x -#else -# define TEXT_PASTE(x) L ## x -#endif -#define TEXT(x) TEXT_PASTE(x) +NAMESPACE_PRIVATE_BEGIN + +#define TEXT_PASTE(X) X +#define WTEXT_PASTE(X) L##X +#define U8TEXT_PASTE(X) u8##X +#define U16TEXT_PASTE(X) u##X +#define U32TEXT_PASTE(X) U##X + +NAMESPACE_PRIVATE_END + +#define TEXT(X) TEXT_PASTE(X) +#define WTEXT(X) WTEXT_PASTE(X) +#define U8TEXT(X) U8TEXT_PASTE(X) +#define U16TEXT(X) U16TEXT_PASTE(X) +#define U32TEXT(X) U32TEXT_PASTE(X) NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) diff --git a/Redcraft.Utility/Source/Public/String/Char.h b/Redcraft.Utility/Source/Public/String/Char.h new file mode 100644 index 0000000..adcdc2d --- /dev/null +++ b/Redcraft.Utility/Source/Public/String/Char.h @@ -0,0 +1,613 @@ +#pragma once + +#include "CoreTypes.h" +#include "TypeTraits/TypeTraits.h" +#include "Miscellaneous/AssertionMacros.h" + +#include +#include + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +template +concept CCharType = CSameAs || CSameAs || CSameAs || CSameAs || CSameAs; + +NAMESPACE_PRIVATE_BEGIN + +template +struct TLiteral; + +template <> +struct TLiteral +{ + FORCEINLINE static constexpr const char Select(const char X, const wchar_t , const char8_t , const char16_t , const char32_t ) { return X; } + FORCEINLINE static constexpr const char* Select(const char* X, const wchar_t*, const char8_t*, const char16_t*, const char32_t*) { return X; } +}; + +template <> +struct TLiteral +{ + FORCEINLINE static constexpr const wchar_t Select(const char , const wchar_t X, const char8_t , const char16_t , const char32_t ) { return X; } + FORCEINLINE static constexpr const wchar_t* Select(const char*, const wchar_t* X, const char8_t*, const char16_t*, const char32_t*) { return X; } +}; + +template <> +struct TLiteral +{ + FORCEINLINE static constexpr const char8_t Select(const char , const wchar_t , const char8_t X, const char16_t , const char32_t ) { return X; } + FORCEINLINE static constexpr const char8_t* Select(const char*, const wchar_t*, const char8_t* X, const char16_t*, const char32_t*) { return X; } +}; + +template <> +struct TLiteral +{ + FORCEINLINE static constexpr const char16_t Select(const char , const wchar_t , const char8_t , const char16_t X, const char32_t ) { return X; } + FORCEINLINE static constexpr const char16_t* Select(const char*, const wchar_t*, const char8_t*, const char16_t* X, const char32_t*) { return X; } +}; + +template <> +struct TLiteral +{ + FORCEINLINE static constexpr const char32_t Select(const char , const wchar_t , const char8_t , const char16_t , const char32_t X) { return X; } + FORCEINLINE static constexpr const char32_t* Select(const char*, const wchar_t*, const char8_t*, const char16_t*, const char32_t* 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_PRIVATE::TLiteral::Select(StringLiteral, WTEXT(StringLiteral), U8TEXT(StringLiteral), U16TEXT(StringLiteral), U32TEXT(StringLiteral)) + +/** Set of utility functions operating on a single character. Implemented based on ISO 30112 "i18n" */ +template +struct TChar +{ + using CharType = T; + + inline static constexpr CharType NONE = CharType(-1); + + FORCEINLINE static constexpr bool IsAlnum(CharType InChar) + { + if constexpr (CSameAs) + { + return NAMESPACE_STD::isalnum(static_cast(InChar)); + } + else if constexpr (CSameAs) + { + return NAMESPACE_STD::iswalnum(InChar); + } + else + { + return IsAlpha(InChar) || IsDigit(InChar); + } + } + + FORCEINLINE static constexpr bool IsAlpha(CharType InChar) + { + if constexpr (CSameAs) + { + return NAMESPACE_STD::isalpha(static_cast(InChar)); + } + else if constexpr (CSameAs) + { + return NAMESPACE_STD::iswalpha(InChar); + } + else if constexpr (CSameAs) + { + /* + * BASIC LATIN + * ..;..; + */ + if ((InChar >= U8TEXT('\u0041') && InChar <= U8TEXT('\u005A')) || + (InChar >= U8TEXT('\u0061') && InChar <= U8TEXT('\u007A'))) + return true; + + return false; + } + else + { + static_assert(sizeof(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr bool IsLower(CharType InChar) + { + if constexpr (CSameAs) + { + return NAMESPACE_STD::islower(static_cast(InChar)); + } + else if constexpr (CSameAs) + { + return NAMESPACE_STD::iswlower(InChar); + } + else if constexpr (CSameAs) + { + /* + * BASIC LATIN + * ..; + */ + if (InChar >= U8TEXT('\u0061') && InChar <= U8TEXT('\u007A')) return true; + + return false; + } + else + { + static_assert(sizeof(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr bool IsUpper(CharType InChar) + { + if constexpr (CSameAs) + { + return NAMESPACE_STD::isupper(static_cast(InChar)); + } + else if constexpr (CSameAs) + { + return NAMESPACE_STD::iswupper(InChar); + } + else if constexpr (CSameAs) + { + /* + * BASIC LATIN + * ..; + */ + if (InChar >= U8TEXT('\u0041') && InChar <= U8TEXT('\u005A')) return true; + + return false; + } + else + { + static_assert(sizeof(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr bool IsDigit(CharType InChar) + { + /* ..; */ + return (InChar >= LITERAL(CharType, '0') && InChar <= LITERAL(CharType, '9')); + } + + FORCEINLINE static constexpr bool IsDigit(CharType InChar, int Base) + { + checkf(Base >= 2 && Base <= 36, TEXT("Base must be in the range [2, 36].")); + + /* ..;..;..; */ + return + (InChar >= LITERAL(CharType, '0') && InChar < LITERAL(CharType, '0') + Base ) || + (InChar >= LITERAL(CharType, 'a') && InChar < LITERAL(CharType, 'a') + Base - 10) || + (InChar >= LITERAL(CharType, 'A') && InChar < LITERAL(CharType, 'A') + Base - 10); + } + + FORCEINLINE static constexpr bool IsCntrl(CharType InChar) + { + if constexpr (CSameAs) + { + return NAMESPACE_STD::iscntrl(static_cast(InChar)); + } + else if constexpr (CSameAs) + { + return NAMESPACE_STD::iswcntrl(InChar); + } + else if constexpr (CSameAs) + { + /* ..;; */ + return (InChar >= U8TEXT('\u0000') && InChar <= U8TEXT('\u001F')) || InChar == U8TEXT('\u007F'); + } + else if constexpr (CSameAs) + { + /* ..;..;;; */ + return + (InChar >= U16TEXT('\u0000') && InChar <= U16TEXT('\u001F')) || + (InChar >= U16TEXT('\u007F') && InChar <= U16TEXT('\u009F')) || + (InChar == U16TEXT('\u2028') || InChar == U16TEXT('\u2029')); + } + else if constexpr (CSameAs) + { + /* ..;..;;; */ + return + (InChar >= U32TEXT('\u0000') && InChar <= U32TEXT('\u001F')) || + (InChar >= U32TEXT('\u007F') && InChar <= U32TEXT('\u009F')) || + (InChar == U32TEXT('\u2028') || InChar == U32TEXT('\u2029')); + } + else + { + static_assert(sizeof(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr bool IsGraph(CharType InChar) + { + if constexpr (CSameAs) + { + return NAMESPACE_STD::isgraph(static_cast(InChar)); + } + else if constexpr (CSameAs) + { + return NAMESPACE_STD::iswgraph(InChar); + } + else if constexpr (CSameAs) + { + /* + * BASIC LATIN + * ..; + */ + if (InChar >= U8TEXT('\u0021') && InChar <= U8TEXT('\u007E')) return true; + + return false; + } + else + { + static_assert(sizeof(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr bool IsSpace(CharType InChar) + { + if constexpr (CSameAs) + { + return NAMESPACE_STD::isspace(static_cast(InChar)); + } + else if constexpr (CSameAs) + { + return NAMESPACE_STD::iswspace(InChar); + } + else if constexpr (CSameAs) + { + /* + * ISO/IEC 6429 + * ..; + */ + if (InChar >= U8TEXT('\u0009') && InChar <= U8TEXT('\u000D')) return true; + + /* + * BASIC LATIN + * ; + */ + if (InChar == U8TEXT('\u0020')) return true; + + return false; + } + else if constexpr (CSameAs) + { + /* + * ISO/IEC 6429 + * ..; + */ + if (InChar >= U16TEXT('\u0009') && InChar <= U16TEXT('\u000D')) return true; + + /* + * BASIC LATIN + * ; + */ + if (InChar == U16TEXT('\u0020')) return true; + + /* + * OGHAM + * ; + */ + if (InChar == U16TEXT('\u1680')) return true; + + /* + * MONGOL + * ; + */ + if (InChar == U16TEXT('\u180E')) return true; + + /* + * GENERAL PUNCTUATION + * ..;..;;;; + */ + 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 + * ; + */ + if (InChar == U16TEXT('\u3000')) return true; + + return false; + } + else if constexpr (CSameAs) + { + /* + * ISO/IEC 6429 + * ..; + */ + if (InChar >= U32TEXT('\u0009') && InChar <= U32TEXT('\u000D')) return true; + + /* + * BASIC LATIN + * ; + */ + if (InChar == U32TEXT('\u0020')) return true; + + /* + * OGHAM + * ; + */ + if (InChar == U32TEXT('\u1680')) return true; + + /* + * MONGOL + * ; + */ + if (InChar == U32TEXT('\u180E')) return true; + + /* + * GENERAL PUNCTUATION + * ..;..;;;; + */ + 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 + * ; + */ + if (InChar == U32TEXT('\u3000')) return true; + + return false; + } + else + { + static_assert(sizeof(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr bool IsBlank(CharType InChar) + { + if constexpr (CSameAs) + { + return NAMESPACE_STD::isblank(static_cast(InChar)); + } + else if constexpr (CSameAs) + { + return NAMESPACE_STD::iswblank(InChar); + } + else if constexpr (CSameAs) + { + /* ;; */ + return InChar == U8TEXT('\u0009') || InChar == U8TEXT('\u0020'); + } + else if constexpr (CSameAs) + { + /* ;;;;..;..;;; */ + 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) + { + /* ;;;;..;..;;; */ + 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(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr bool IsPrint(CharType InChar) + { + if constexpr (CSameAs) + { + return NAMESPACE_STD::isprint(static_cast(InChar)); + } + else if constexpr (CSameAs) + { + return NAMESPACE_STD::iswprint(InChar); + } + else if constexpr (CSameAs) + { + /* + * BASIC LATIN + * ..; + */ + if (InChar >= U8TEXT('\u0020') && InChar <= U8TEXT('\u007E')) return true; + + return false; + } + else + { + static_assert(sizeof(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr bool IsPunct(CharType InChar) + { + if constexpr (CSameAs) + { + return NAMESPACE_STD::ispunct(static_cast(InChar)); + } + else if constexpr (CSameAs) + { + return NAMESPACE_STD::iswpunct(InChar); + } + else if constexpr (CSameAs) + { + /* + * BASIC LATIN + * ..;..;..;..; + */ + 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 + { + static_assert(sizeof(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr CharType ToLower(CharType InChar) + { + if constexpr (CSameAs) + { + return static_cast(NAMESPACE_STD::tolower(static_cast(InChar))); + } + else if constexpr (CSameAs) + { + return static_cast(NAMESPACE_STD::towlower(InChar)); + } + else if constexpr (CSameAs) + { + /* + * BASIC LATIN + * (,);(,);(,);(,); + * (,);(,);(,);(,); + * (,);(,);(,);(,); + * (,);(,);(,);(,); + * (,);(,);(,);(,); + * (,);(,);(,);(,); + * (,);(,); + */ + if (InChar >= U8TEXT('\u0041') && InChar <= U8TEXT('\u005A')) return InChar + U8TEXT('\u0020'); + + return InChar; + } + else + { + static_assert(sizeof(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr CharType ToUpper(CharType InChar) + { + if constexpr (CSameAs) + { + return static_cast(NAMESPACE_STD::toupper(static_cast(InChar))); + } + else if constexpr (CSameAs) + { + return static_cast(NAMESPACE_STD::towupper(InChar)); + } + else if constexpr (CSameAs) + { + /* + * BASIC LATIN + * (,);(,);(,);(,);/ + * (,);(,);(,);(,);/ + * (,);(,);(,);(,);/ + * (,);(,);(,);(,);/ + * (,);(,);(,);(,);/ + * (,);(,);(,);(,);/ + * (,);(,); + */ + if (InChar >= U8TEXT('\u0061') && InChar <= U8TEXT('\u007A')) return InChar - U8TEXT('\u0020'); + + return InChar; + } + else + { + static_assert(sizeof(CharType) == -1, "Unsupported character type"); + } + } + + FORCEINLINE static constexpr int ToDigit(CharType InChar) + { + switch (InChar) + { + case LITERAL(CharType, '0'): return 0; + case LITERAL(CharType, '1'): return 1; + case LITERAL(CharType, '2'): return 2; + case LITERAL(CharType, '3'): return 3; + case LITERAL(CharType, '4'): return 4; + case LITERAL(CharType, '5'): return 5; + case LITERAL(CharType, '6'): return 6; + case LITERAL(CharType, '7'): return 7; + case LITERAL(CharType, '8'): return 8; + case LITERAL(CharType, '9'): return 9; + case LITERAL(CharType, 'a'): return 10; + case LITERAL(CharType, 'b'): return 11; + case LITERAL(CharType, 'c'): return 12; + case LITERAL(CharType, 'd'): return 13; + case LITERAL(CharType, 'e'): return 14; + case LITERAL(CharType, 'f'): return 15; + case LITERAL(CharType, 'g'): return 16; + case LITERAL(CharType, 'h'): return 17; + case LITERAL(CharType, 'i'): return 18; + case LITERAL(CharType, 'j'): return 19; + case LITERAL(CharType, 'k'): return 20; + case LITERAL(CharType, 'l'): return 21; + case LITERAL(CharType, 'm'): return 22; + case LITERAL(CharType, 'n'): return 23; + case LITERAL(CharType, 'o'): return 24; + case LITERAL(CharType, 'p'): return 25; + case LITERAL(CharType, 'q'): return 26; + case LITERAL(CharType, 'r'): return 27; + case LITERAL(CharType, 's'): return 28; + case LITERAL(CharType, 't'): return 29; + case LITERAL(CharType, 'u'): return 30; + case LITERAL(CharType, 'v'): return 31; + case LITERAL(CharType, 'w'): return 32; + case LITERAL(CharType, 'x'): return 33; + case LITERAL(CharType, 'y'): return 34; + case LITERAL(CharType, 'z'): return 35; + case LITERAL(CharType, 'A'): return 10; + case LITERAL(CharType, 'B'): return 11; + case LITERAL(CharType, 'C'): return 12; + case LITERAL(CharType, 'D'): return 13; + case LITERAL(CharType, 'E'): return 14; + case LITERAL(CharType, 'F'): return 15; + case LITERAL(CharType, 'G'): return 16; + case LITERAL(CharType, 'H'): return 17; + case LITERAL(CharType, 'I'): return 18; + case LITERAL(CharType, 'J'): return 19; + case LITERAL(CharType, 'K'): return 20; + case LITERAL(CharType, 'L'): return 21; + case LITERAL(CharType, 'M'): return 22; + case LITERAL(CharType, 'N'): return 23; + case LITERAL(CharType, 'O'): return 24; + case LITERAL(CharType, 'P'): return 25; + case LITERAL(CharType, 'Q'): return 26; + case LITERAL(CharType, 'R'): return 27; + case LITERAL(CharType, 'S'): return 28; + case LITERAL(CharType, 'T'): return 29; + case LITERAL(CharType, 'U'): return 30; + case LITERAL(CharType, 'V'): return 31; + case LITERAL(CharType, 'W'): return 32; + case LITERAL(CharType, 'X'): return 33; + case LITERAL(CharType, 'Y'): return 34; + case LITERAL(CharType, 'Z'): return 35; + default: return -1; + } + } + + FORCEINLINE static constexpr CharType FromDigit(int InDigit) + { + if (InDigit < 0 || InDigit >= 36) return NONE; + + return LITERAL(CharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit]; + } +}; + +using FChar = TChar; +using FWChar = TChar; +using FU8Char = TChar; +using FU16Char = TChar; +using FU32Char = TChar; + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Public/Testing/StringTesting.h b/Redcraft.Utility/Source/Public/Testing/StringTesting.h new file mode 100644 index 0000000..2370251 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Testing/StringTesting.h @@ -0,0 +1,18 @@ +#pragma once + +#include "CoreTypes.h" + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +NAMESPACE_BEGIN(Testing) + +REDCRAFTUTILITY_API void TestString(); +REDCRAFTUTILITY_API void TestChar(); + +NAMESPACE_END(Testing) + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END