Compare commits
48 Commits
85199119b3
...
0.1.0-expe
Author | SHA1 | Date | |
---|---|---|---|
6cc31f660c | |||
2d79e18b25 | |||
1d5a61f308 | |||
38e1c3f8b7 | |||
8d3fa1ac98 | |||
88e330336a | |||
eca0d90d98 | |||
d8adf47d10 | |||
8a834a9c05 | |||
35f0ba71ab | |||
db7a40cb30 | |||
6a70f0c501 | |||
5629e31d49 | |||
c16da1af53 | |||
88aba14620 | |||
23963e0389 | |||
0c6f33762a | |||
9024957ff2 | |||
68cd2c310a | |||
594acf219a | |||
e498b39d3d | |||
9dd5e74788 | |||
c596882c32 | |||
0e7ee5cde2 | |||
39d12bd7e4 | |||
319d1cc8cb | |||
fc87332845 | |||
22952237df | |||
f817afe6df | |||
a3cebf03ec | |||
262ce1bb67 | |||
bf22397123 | |||
2de1068ad8 | |||
aa572542e2 | |||
db855d27a1 | |||
04bb4be901 | |||
a68a6d16b6 | |||
a92422e8b2 | |||
343007ffd6 | |||
8c228fbf52 | |||
a14fbd90db | |||
1e6beb83f2 | |||
7fb116c577 | |||
566052c8c2 | |||
a0250ebaf8 | |||
f88cf7ef3e | |||
e6d525f2c3 | |||
dd3a366c14 |
462
Redcraft.Utility/Source/Private/Miscellaneous/Console.cpp
Normal file
462
Redcraft.Utility/Source/Private/Miscellaneous/Console.cpp
Normal file
@ -0,0 +1,462 @@
|
||||
#include "Miscellaneous/Console.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
# undef TEXT
|
||||
# include <windows.h>
|
||||
#elif PLATFORM_LINUX
|
||||
# include <sys/ioctl.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
NODISCARD bool InitANSIConsole()
|
||||
{
|
||||
static bool bResult = []
|
||||
{
|
||||
HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (Console == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
DWORD ConsoleMode = 0;
|
||||
|
||||
if (!GetConsoleMode(Console, &ConsoleMode)) return false;
|
||||
|
||||
ConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
|
||||
if (!SetConsoleMode(Console, ConsoleMode)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
();
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
EColor GForegroundColor = EColor::Default;
|
||||
EColor GBackgroundColor = EColor::Default;
|
||||
|
||||
EColor GetForegroundColor()
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
if (InitANSIConsole()) return GForegroundColor;
|
||||
|
||||
const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (Console == INVALID_HANDLE_VALUE) return EColor::Default;
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return EColor::Default;
|
||||
|
||||
const WORD Color = ConsoleInfo.wAttributes;
|
||||
|
||||
EColor Result = EColor::Black;
|
||||
|
||||
if (Color & FOREGROUND_RED) Result |= EColor::Red;
|
||||
if (Color & FOREGROUND_GREEN) Result |= EColor::Green;
|
||||
if (Color & FOREGROUND_BLUE) Result |= EColor::Blue;
|
||||
if (Color & FOREGROUND_INTENSITY) Result |= EColor::Intensity;
|
||||
|
||||
return Result;
|
||||
}
|
||||
# endif
|
||||
|
||||
return GForegroundColor;
|
||||
}
|
||||
|
||||
EColor GetBackgroundColor()
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
if (InitANSIConsole()) return GBackgroundColor;
|
||||
|
||||
const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (Console == INVALID_HANDLE_VALUE) return EColor::Default;
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return EColor::Default;
|
||||
|
||||
const WORD Color = ConsoleInfo.wAttributes;
|
||||
|
||||
EColor Result = EColor::Black;
|
||||
|
||||
if (Color & BACKGROUND_RED) Result |= EColor::Red;
|
||||
if (Color & BACKGROUND_GREEN) Result |= EColor::Green;
|
||||
if (Color & BACKGROUND_BLUE) Result |= EColor::Blue;
|
||||
if (Color & BACKGROUND_INTENSITY) Result |= EColor::Intensity;
|
||||
|
||||
return Result;
|
||||
}
|
||||
# endif
|
||||
|
||||
return GBackgroundColor;
|
||||
}
|
||||
|
||||
EColor SetForegroundColor(EColor InColor)
|
||||
{
|
||||
if (IsOutputRedirected()) return GetForegroundColor();
|
||||
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
if (!InitANSIConsole())
|
||||
{
|
||||
const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (Console == INVALID_HANDLE_VALUE) return GetForegroundColor();
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return GetForegroundColor();
|
||||
|
||||
WORD Color = ConsoleInfo.wAttributes & ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
|
||||
|
||||
if (InColor == EColor::Default) InColor = EColor::White;
|
||||
|
||||
if (!!(InColor & EColor::Red)) Color |= FOREGROUND_RED;
|
||||
if (!!(InColor & EColor::Green)) Color |= FOREGROUND_GREEN;
|
||||
if (!!(InColor & EColor::Blue)) Color |= FOREGROUND_BLUE;
|
||||
if (!!(InColor & EColor::Intensity)) Color |= FOREGROUND_INTENSITY;
|
||||
|
||||
if (!SetConsoleTextAttribute(Console, Color)) return GetForegroundColor();
|
||||
|
||||
return InColor;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
# if PLATFORM_WINDOWS || PLATFORM_LINUX
|
||||
{
|
||||
int Result;
|
||||
|
||||
switch (InColor)
|
||||
{
|
||||
case EColor::Black: Result = std::fputs("\033[30m", stdout); break;
|
||||
case EColor::Red: Result = std::fputs("\033[31m", stdout); break;
|
||||
case EColor::Green: Result = std::fputs("\033[32m", stdout); break;
|
||||
case EColor::Yellow: Result = std::fputs("\033[33m", stdout); break;
|
||||
case EColor::Blue: Result = std::fputs("\033[34m", stdout); break;
|
||||
case EColor::Magenta: Result = std::fputs("\033[35m", stdout); break;
|
||||
case EColor::Cyan: Result = std::fputs("\033[36m", stdout); break;
|
||||
case EColor::White: Result = std::fputs("\033[37m", stdout); break;
|
||||
case EColor::BrightBlack: Result = std::fputs("\033[90m", stdout); break;
|
||||
case EColor::BrightRed: Result = std::fputs("\033[91m", stdout); break;
|
||||
case EColor::BrightGreen: Result = std::fputs("\033[92m", stdout); break;
|
||||
case EColor::BrightYellow: Result = std::fputs("\033[93m", stdout); break;
|
||||
case EColor::BrightBlue: Result = std::fputs("\033[94m", stdout); break;
|
||||
case EColor::BrightMagenta: Result = std::fputs("\033[95m", stdout); break;
|
||||
case EColor::BrightCyan: Result = std::fputs("\033[96m", stdout); break;
|
||||
case EColor::BrightWhite: Result = std::fputs("\033[97m", stdout); break;
|
||||
default: Result = std::fputs("\033[39m", stdout); break;
|
||||
}
|
||||
|
||||
if (Result == EOF) return GetForegroundColor();
|
||||
|
||||
return GForegroundColor = InColor;
|
||||
}
|
||||
# endif
|
||||
|
||||
return GetForegroundColor();
|
||||
}
|
||||
|
||||
EColor SetBackgroundColor(EColor InColor)
|
||||
{
|
||||
if (IsOutputRedirected()) return GetBackgroundColor();
|
||||
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
if (!InitANSIConsole())
|
||||
{
|
||||
const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (Console == INVALID_HANDLE_VALUE) return GetBackgroundColor();
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return GetBackgroundColor();
|
||||
|
||||
WORD Color = ConsoleInfo.wAttributes & ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
|
||||
|
||||
if (InColor == EColor::Default) InColor = EColor::Black;
|
||||
|
||||
if (!!(InColor & EColor::Red)) Color |= BACKGROUND_RED;
|
||||
if (!!(InColor & EColor::Green)) Color |= BACKGROUND_GREEN;
|
||||
if (!!(InColor & EColor::Blue)) Color |= BACKGROUND_BLUE;
|
||||
if (!!(InColor & EColor::Intensity)) Color |= BACKGROUND_INTENSITY;
|
||||
|
||||
if (!SetConsoleTextAttribute(Console, Color)) return GetBackgroundColor();
|
||||
|
||||
return InColor;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
# if PLATFORM_WINDOWS || PLATFORM_LINUX
|
||||
{
|
||||
int Result;
|
||||
|
||||
switch (InColor)
|
||||
{
|
||||
case EColor::Black: Result = std::fputs("\033[40m", stdout); break;
|
||||
case EColor::Red: Result = std::fputs("\033[41m", stdout); break;
|
||||
case EColor::Green: Result = std::fputs("\033[42m", stdout); break;
|
||||
case EColor::Yellow: Result = std::fputs("\033[43m", stdout); break;
|
||||
case EColor::Blue: Result = std::fputs("\033[44m", stdout); break;
|
||||
case EColor::Magenta: Result = std::fputs("\033[45m", stdout); break;
|
||||
case EColor::Cyan: Result = std::fputs("\033[46m", stdout); break;
|
||||
case EColor::White: Result = std::fputs("\033[47m", stdout); break;
|
||||
case EColor::BrightBlack: Result = std::fputs("\033[100m", stdout); break;
|
||||
case EColor::BrightRed: Result = std::fputs("\033[101m", stdout); break;
|
||||
case EColor::BrightGreen: Result = std::fputs("\033[102m", stdout); break;
|
||||
case EColor::BrightYellow: Result = std::fputs("\033[103m", stdout); break;
|
||||
case EColor::BrightBlue: Result = std::fputs("\033[104m", stdout); break;
|
||||
case EColor::BrightMagenta: Result = std::fputs("\033[105m", stdout); break;
|
||||
case EColor::BrightCyan: Result = std::fputs("\033[106m", stdout); break;
|
||||
case EColor::BrightWhite: Result = std::fputs("\033[107m", stdout); break;
|
||||
default: Result = std::fputs("\033[49m", stdout); break;
|
||||
}
|
||||
|
||||
if (Result == EOF) return GetBackgroundColor();
|
||||
|
||||
return GBackgroundColor = InColor;
|
||||
}
|
||||
# endif
|
||||
|
||||
return GetBackgroundColor();
|
||||
}
|
||||
|
||||
uint GetWindowWidth()
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (Console == INVALID_HANDLE_VALUE) return static_cast<uint>(-1);
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return static_cast<uint>(-1);
|
||||
|
||||
return static_cast<uint>(ConsoleInfo.srWindow.Right - ConsoleInfo.srWindow.Left + 1);
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
winsize Size;
|
||||
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &Size) == -1) return static_cast<uint>(-1);
|
||||
|
||||
return static_cast<uint>(Size.ws_col);
|
||||
}
|
||||
# endif
|
||||
|
||||
return static_cast<uint>(-1);
|
||||
}
|
||||
|
||||
uint GetWindowHeight()
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
const HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (Console == INVALID_HANDLE_VALUE) return static_cast<uint>(-1);
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(Console, &ConsoleInfo)) return static_cast<uint>(-1);
|
||||
|
||||
return static_cast<uint>(ConsoleInfo.srWindow.Bottom - ConsoleInfo.srWindow.Top + 1);
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
winsize Size;
|
||||
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &Size) == -1) return static_cast<uint>(-1);
|
||||
|
||||
return static_cast<uint>(Size.ws_row);
|
||||
}
|
||||
# endif
|
||||
|
||||
return static_cast<uint>(-1);
|
||||
}
|
||||
|
||||
bool IsInputRedirected()
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
const HANDLE StandardInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
if (StandardInput == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
DWORD FileType = GetFileType(StandardInput);
|
||||
|
||||
return FileType != FILE_TYPE_CHAR;
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
return isatty(fileno(stdin)) == 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsOutputRedirected()
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
const HANDLE StandardOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (StandardOutput == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
DWORD FileType = GetFileType(StandardOutput);
|
||||
|
||||
return FileType != FILE_TYPE_CHAR;
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
return isatty(fileno(stdout)) == 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsErrorRedirected()
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
const HANDLE StandardError = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
if (StandardError == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
DWORD FileType = GetFileType(StandardError);
|
||||
|
||||
return FileType != FILE_TYPE_CHAR;
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
return isatty(fileno(stderr)) == 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
if (IsOutputRedirected()) return;
|
||||
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
std::system("cls");
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
Ignore = std::fputs("\033[2J\033[1;1H", stdout);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
char Input(bool bEcho)
|
||||
{
|
||||
if (bEcho || IsOutputRedirected())
|
||||
{
|
||||
const int Result = std::getchar();
|
||||
|
||||
if (Result == EOF) return static_cast<char>(-1);
|
||||
|
||||
return static_cast<char>(Result);
|
||||
}
|
||||
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
const HANDLE Console = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
if (Console == INVALID_HANDLE_VALUE) return static_cast<char>(-1);
|
||||
|
||||
DWORD ConsoleMode = 0;
|
||||
|
||||
GetConsoleMode(Console, &ConsoleMode);
|
||||
|
||||
SetConsoleMode(Console, ConsoleMode & ~ENABLE_ECHO_INPUT);
|
||||
|
||||
const char Result = Input();
|
||||
|
||||
SetConsoleMode(Console, ConsoleMode);
|
||||
|
||||
return Result;
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{ }
|
||||
# endif
|
||||
|
||||
return static_cast<char>(-1);
|
||||
}
|
||||
|
||||
FString InputLn(bool bEcho)
|
||||
{
|
||||
if (bEcho || IsOutputRedirected())
|
||||
{
|
||||
FString Result;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const int Char = std::getchar();
|
||||
|
||||
if (Char == EOF || Char == '\n') break;
|
||||
|
||||
Result.PushBack(static_cast<char>(Char));
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
const HANDLE Console = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
if (Console == INVALID_HANDLE_VALUE) return "";
|
||||
|
||||
DWORD ConsoleMode = 0;
|
||||
|
||||
GetConsoleMode(Console, &ConsoleMode);
|
||||
|
||||
SetConsoleMode(Console, ConsoleMode & ~ENABLE_ECHO_INPUT);
|
||||
|
||||
const FString Result = InputLn();
|
||||
|
||||
SetConsoleMode(Console, ConsoleMode);
|
||||
|
||||
return Result;
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{ }
|
||||
# endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Print(char Char)
|
||||
{
|
||||
return std::putchar(Char) != EOF;
|
||||
}
|
||||
|
||||
bool Error(char Char)
|
||||
{
|
||||
return std::fputc(Char, stderr) != EOF;
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
596
Redcraft.Utility/Source/Private/Miscellaneous/FileSystem.cpp
Normal file
596
Redcraft.Utility/Source/Private/Miscellaneous/FileSystem.cpp
Normal file
@ -0,0 +1,596 @@
|
||||
#include <Miscellaneous/FileSystem.h>
|
||||
|
||||
#include "Numerics/Bit.h"
|
||||
#include "Numerics/Math.h"
|
||||
#include "Templates/ScopeHelper.h"
|
||||
#include "Containers/StaticArray.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
# undef TEXT
|
||||
# include <windows.h>
|
||||
# undef CreateDirectory
|
||||
#elif PLATFORM_LINUX
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4996)
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(FileSystem)
|
||||
|
||||
bool LoadFileToArray(TArray<uint8>& Result, FStringView Path)
|
||||
{
|
||||
if (!FileSystem::Exists(Path)) return false;
|
||||
|
||||
FILE* File = std::fopen(*Path, "rb");
|
||||
|
||||
if (File == nullptr) return false;
|
||||
|
||||
auto FileGuard = TScopeCallback([=] { Ignore = std::fclose(File); });
|
||||
|
||||
if (std::fseek(File, 0, SEEK_END) != 0) return false;
|
||||
|
||||
const long Length = std::ftell(File);
|
||||
|
||||
if (!Math::IsWithin(Length, 0, TNumericLimits<long>::Max())) return false;
|
||||
|
||||
if (std::fseek(File, 0, SEEK_SET) != 0) return false;
|
||||
|
||||
Result.SetNum(Length);
|
||||
|
||||
if (std::fread(Result.GetData(), sizeof(uint8), Length, File) != static_cast<size_t>(Length)) return false;
|
||||
|
||||
FileGuard.Release();
|
||||
|
||||
if (std::fclose(File) != 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveArrayToFile(TArrayView<const uint8> Data, FStringView Path)
|
||||
{
|
||||
FILE* File = std::fopen(*Path, "wb");
|
||||
|
||||
if (File == nullptr) return false;
|
||||
|
||||
auto FileGuard = TScopeCallback([=] { Ignore = std::fclose(File); });
|
||||
|
||||
if (std::fwrite(Data.GetData(), sizeof(uint8), Data.Num(), File) != Data.Num()) return false;
|
||||
|
||||
FileGuard.Release();
|
||||
|
||||
if (std::fclose(File) != 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <CCharType T>
|
||||
bool LoadFileToString(TString<T>& Result, FStringView Path, FileSystem::EEncoding Encoding /* = FileSystem::EEncoding::Default */, bool bVerify /* = false */)
|
||||
{
|
||||
if (!FileSystem::Exists(Path)) return false;
|
||||
|
||||
FILE* File = std::fopen(*Path, "rb");
|
||||
|
||||
if (File == nullptr) return false;
|
||||
|
||||
auto FileGuard = TScopeCallback([=] { Ignore = std::fclose(File); });
|
||||
|
||||
if (std::fseek(File, 0, SEEK_END) != 0) return false;
|
||||
|
||||
long Length = std::ftell(File);
|
||||
|
||||
if (!Math::IsWithin(Length, 0, TNumericLimits<long>::Max())) return false;
|
||||
|
||||
if (std::fseek(File, 0, SEEK_SET) != 0) return false;
|
||||
|
||||
TStaticArray<uint8, 4> Buffer = { 0xAA, 0xAA, 0xAA, 0xAA };
|
||||
|
||||
Ignore = std::fread(Buffer.GetData(), sizeof(uint8), Buffer.Num(), File);
|
||||
|
||||
// Auto-detect the encoding if it is not specified.
|
||||
if (Encoding == FileSystem::EEncoding::Default)
|
||||
{
|
||||
// Check if the file is a UTF-32 encoded file.
|
||||
if (Buffer[0] == 0x00 && Buffer[1] == 0x00 && Buffer[2] == 0xFE && Buffer[3] == 0xFF) Encoding = FileSystem::EEncoding::UTF32BE;
|
||||
else if (Buffer[0] == 0xFF && Buffer[1] == 0xFE && Buffer[2] == 0x00 && Buffer[3] == 0x00) Encoding = FileSystem::EEncoding::UTF32LE;
|
||||
|
||||
// Check if the file is a UTF-16 encoded file.
|
||||
else if (Buffer[0] == 0xFF && Buffer[1] == 0xFE) Encoding = FileSystem::EEncoding::UTF16LE;
|
||||
else if (Buffer[0] == 0xFE && Buffer[1] == 0xFF) Encoding = FileSystem::EEncoding::UTF16BE;
|
||||
|
||||
// Check if the file is a UTF-8 encoded file.
|
||||
else if (Buffer[0] == 0xEF && Buffer[1] == 0xBB && Buffer[2] == 0xBF) Encoding = FileSystem::EEncoding::UTF8;
|
||||
|
||||
// Check if the file is a wide character encoded file.
|
||||
else if (Buffer[0] == 0x00 || Buffer[1] == 0x00 || Buffer[2] == 0x00 || Buffer[3] == 0x00) Encoding = FileSystem::EEncoding::Wide;
|
||||
|
||||
// Check if the file is a narrow character encoded file.
|
||||
else Encoding = FileSystem::EEncoding::Narrow;
|
||||
}
|
||||
|
||||
// Jump to the BOM character if the file is a UTF-8, UTF-16 or UTF-32 encoded file.
|
||||
switch (Encoding)
|
||||
{
|
||||
case FileSystem::EEncoding::Narrow:
|
||||
case FileSystem::EEncoding::Wide: { Length -= 0; if (std::fseek(File, 0, SEEK_SET) != 0) return false; } break;
|
||||
case FileSystem::EEncoding::UTF8: if (Buffer[0] == 0xEF && Buffer[1] == 0xBB && Buffer[2] == 0xBF) { Length -= 3; if (std::fseek(File, 3, SEEK_SET) != 0) return false; } break;
|
||||
case FileSystem::EEncoding::UTF16BE: if (Buffer[0] == 0xFE && Buffer[1] == 0xFF) { Length -= 2; if (std::fseek(File, 2, SEEK_SET) != 0) return false; } break;
|
||||
case FileSystem::EEncoding::UTF16LE: if (Buffer[0] == 0xFF && Buffer[1] == 0xFE) { Length -= 2; if (std::fseek(File, 2, SEEK_SET) != 0) return false; } break;
|
||||
case FileSystem::EEncoding::UTF32BE: if (Buffer[0] == 0x00 && Buffer[1] == 0x00 && Buffer[2] == 0xFE && Buffer[3] == 0xFF) { Length -= 4; if (std::fseek(File, 4, SEEK_SET) != 0) return false; } break;
|
||||
case FileSystem::EEncoding::UTF32LE: if (Buffer[0] == 0xFF && Buffer[1] == 0xFE && Buffer[2] == 0x00 && Buffer[3] == 0x00) { Length -= 4; if (std::fseek(File, 4, SEEK_SET) != 0) return false; } break;
|
||||
default: check_no_entry();
|
||||
}
|
||||
|
||||
check(Math::EEndian::Native == Math::EEndian::Big || Math::EEndian::Native == Math::EEndian::Little);
|
||||
|
||||
const bool bByteSwap =
|
||||
Math::EEndian::Native == Math::EEndian::Big ? Encoding == FileSystem::EEncoding::UTF16LE || Encoding == FileSystem::EEncoding::UTF32LE :
|
||||
Math::EEndian::Native == Math::EEndian::Little ? Encoding == FileSystem::EEncoding::UTF16BE || Encoding == FileSystem::EEncoding::UTF32BE : false;
|
||||
|
||||
const auto LoadImpl = [File, Length, bByteSwap]<typename U>(TString<U>& String) -> bool
|
||||
{
|
||||
if (Length % sizeof(U) != 0) return false;
|
||||
|
||||
String.Reserve(Length / sizeof(U));
|
||||
|
||||
while (true)
|
||||
{
|
||||
U Char;
|
||||
|
||||
const size_t ReadNum = std::fread(&Char, 1, sizeof(U), File);
|
||||
|
||||
if (ReadNum == 0) break;
|
||||
|
||||
if (ReadNum != sizeof(U)) return false;
|
||||
|
||||
if (bByteSwap) Char = Math::ByteSwap(static_cast<TMakeUnsigned<U>>(Char));
|
||||
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
if (!String.IsEmpty() && String.Back() == LITERAL(U, '\r') && Char == LITERAL(U, '\n'))
|
||||
{
|
||||
String.PopBack();
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
String.PushBack(Char);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool bCompatible = false;
|
||||
|
||||
if constexpr (CSameAs<T, char>) bCompatible |= Encoding == FileSystem::EEncoding::Narrow;
|
||||
else if constexpr (CSameAs<T, wchar>) bCompatible |= Encoding == FileSystem::EEncoding::Wide;
|
||||
else if constexpr (CSameAs<T, u8char>) bCompatible |= Encoding == FileSystem::EEncoding::UTF8;
|
||||
else if constexpr (CSameAs<T, u16char>) bCompatible |= Encoding == FileSystem::EEncoding::UTF16BE || Encoding == FileSystem::EEncoding::UTF16LE;
|
||||
else if constexpr (CSameAs<T, u32char>) bCompatible |= Encoding == FileSystem::EEncoding::UTF32BE || Encoding == FileSystem::EEncoding::UTF32LE;
|
||||
|
||||
else static_assert(sizeof(T) == -1, "Unsupported character type");
|
||||
|
||||
if (!bCompatible || bVerify)
|
||||
{
|
||||
switch (Encoding)
|
||||
{
|
||||
case FileSystem::EEncoding::Narrow: { FString Temp; if (!LoadImpl(Temp)) return false; if (!Result.DecodeFrom(Temp)) return false; break; }
|
||||
case FileSystem::EEncoding::Wide: { FWString Temp; if (!LoadImpl(Temp)) return false; if (!Result.DecodeFrom(Temp)) return false; break; }
|
||||
case FileSystem::EEncoding::UTF8: { FU8String Temp; if (!LoadImpl(Temp)) return false; if (!Result.DecodeFrom(Temp)) return false; break; }
|
||||
case FileSystem::EEncoding::UTF16BE:
|
||||
case FileSystem::EEncoding::UTF16LE: { FU16String Temp; if (!LoadImpl(Temp)) return false; if (!Result.DecodeFrom(Temp)) return false; break; }
|
||||
case FileSystem::EEncoding::UTF32BE:
|
||||
case FileSystem::EEncoding::UTF32LE: { FU32String Temp; if (!LoadImpl(Temp)) return false; if (!Result.DecodeFrom(Temp)) return false; break; }
|
||||
default: check_no_entry();
|
||||
}
|
||||
}
|
||||
|
||||
else if (!LoadImpl(Result)) return false;
|
||||
|
||||
FileGuard.Release();
|
||||
|
||||
if (std::fclose(File) != 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template REDCRAFTUTILITY_API bool LoadFileToString<char> (FString&, FStringView, FileSystem::EEncoding, bool);
|
||||
template REDCRAFTUTILITY_API bool LoadFileToString<wchar> (FWString&, FStringView, FileSystem::EEncoding, bool);
|
||||
template REDCRAFTUTILITY_API bool LoadFileToString<u8char> (FU8String&, FStringView, FileSystem::EEncoding, bool);
|
||||
template REDCRAFTUTILITY_API bool LoadFileToString<u16char>(FU16String&, FStringView, FileSystem::EEncoding, bool);
|
||||
template REDCRAFTUTILITY_API bool LoadFileToString<u32char>(FU32String&, FStringView, FileSystem::EEncoding, bool);
|
||||
|
||||
template <CCharType T>
|
||||
bool SaveStringToFile(TStringView<T> String, FStringView Path, FileSystem::EEncoding Encoding /* = FileSystem::EEncoding::Default */, bool bWithBOM /* = true */)
|
||||
{
|
||||
bool bCompatible = Encoding == FileSystem::EEncoding::Default;
|
||||
|
||||
if constexpr (CSameAs<T, char>) bCompatible |= Encoding == FileSystem::EEncoding::Narrow;
|
||||
else if constexpr (CSameAs<T, wchar>) bCompatible |= Encoding == FileSystem::EEncoding::Wide;
|
||||
else if constexpr (CSameAs<T, u8char>) bCompatible |= Encoding == FileSystem::EEncoding::UTF8;
|
||||
else if constexpr (CSameAs<T, u16char>) bCompatible |= Encoding == FileSystem::EEncoding::UTF16BE || Encoding == FileSystem::EEncoding::UTF16LE;
|
||||
else if constexpr (CSameAs<T, u32char>) bCompatible |= Encoding == FileSystem::EEncoding::UTF32BE || Encoding == FileSystem::EEncoding::UTF32LE;
|
||||
|
||||
else static_assert(sizeof(T) == -1, "Unsupported character type");
|
||||
|
||||
if (bCompatible)
|
||||
{
|
||||
FILE* File = std::fopen(*Path, "wb");
|
||||
|
||||
if (File == nullptr) return false;
|
||||
|
||||
auto FileGuard = TScopeCallback([=] { Ignore = std::fclose(File); });
|
||||
|
||||
if (bWithBOM)
|
||||
{
|
||||
if constexpr (CSameAs<T, u8char>)
|
||||
{
|
||||
if (std::fwrite(U8TEXT("\uFEFF"), 1, 3, File) != 3) return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<T, u16char>)
|
||||
{
|
||||
constexpr TStaticArray<uint8, 2> BufferBE = { 0xFE, 0xFF };
|
||||
constexpr TStaticArray<uint8, 2> BufferLE = { 0xFF, 0xFE };
|
||||
|
||||
if (Encoding == FileSystem::EEncoding::UTF16BE) { if (std::fwrite(BufferBE.GetData(), 1, BufferBE.Num(), File) != BufferBE.Num()) return false; }
|
||||
else if (Encoding == FileSystem::EEncoding::UTF16LE) { if (std::fwrite(BufferLE.GetData(), 1, BufferLE.Num(), File) != BufferLE.Num()) return false; }
|
||||
|
||||
else if (std::fwrite(U16TEXT("\uFEFF"), 1, sizeof(T), File) != sizeof(T)) return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<T, u32char>)
|
||||
{
|
||||
constexpr TStaticArray<uint8, 4> BufferBE = { 0x00, 0x00, 0xFE, 0xFF };
|
||||
constexpr TStaticArray<uint8, 4> BufferLE = { 0xFF, 0xFE, 0x00, 0x00 };
|
||||
|
||||
if (Encoding == FileSystem::EEncoding::UTF32BE) { if (std::fwrite(BufferBE.GetData() , 1, BufferBE.Num(), File) != BufferBE.Num()) return false; }
|
||||
else if (Encoding == FileSystem::EEncoding::UTF32LE) { if (std::fwrite(BufferLE.GetData() , 1, BufferLE.Num(), File) != BufferLE.Num()) return false; }
|
||||
|
||||
else if (std::fwrite(U32TEXT("\uFEFF"), 1, sizeof(T), File) != sizeof(T)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
check(Math::EEndian::Native == Math::EEndian::Big || Math::EEndian::Native == Math::EEndian::Little);
|
||||
|
||||
const bool bByteSwap =
|
||||
Math::EEndian::Native == Math::EEndian::Big ? Encoding == FileSystem::EEncoding::UTF16LE || Encoding == FileSystem::EEncoding::UTF32LE :
|
||||
Math::EEndian::Native == Math::EEndian::Little ? Encoding == FileSystem::EEncoding::UTF16BE || Encoding == FileSystem::EEncoding::UTF32BE : false;
|
||||
|
||||
for (T Char : String)
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
if (Char == LITERAL(T, '\n'))
|
||||
{
|
||||
T Return = LITERAL(T, '\r');
|
||||
|
||||
if (bByteSwap) Return = Math::ByteSwap(static_cast<TMakeUnsigned<T>>(Return));
|
||||
|
||||
if (std::fwrite(&Return, 1, sizeof(T), File) != sizeof(T)) return false;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
if (bByteSwap) Char = Math::ByteSwap(static_cast<TMakeUnsigned<T>>(Char));
|
||||
|
||||
if (std::fwrite(&Char, 1, sizeof(T), File) != sizeof(T)) return false;
|
||||
}
|
||||
|
||||
FileGuard.Release();
|
||||
|
||||
if (std::fclose(File) != 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FString PathWithNull;
|
||||
|
||||
PathWithNull.Reserve(Path.Num() + 1);
|
||||
|
||||
PathWithNull += Path;
|
||||
PathWithNull += '\0';
|
||||
|
||||
switch (Encoding)
|
||||
{
|
||||
case FileSystem::EEncoding::Narrow: { FString Temp; if (!Temp.DecodeFrom(String)) return false; if (!FileSystem::SaveStringToFile(Temp, PathWithNull, FileSystem::EEncoding::Narrow, bWithBOM)) return false; break; }
|
||||
case FileSystem::EEncoding::Wide: { FWString Temp; if (!Temp.DecodeFrom(String)) return false; if (!FileSystem::SaveStringToFile(Temp, PathWithNull, FileSystem::EEncoding::Wide, bWithBOM)) return false; break; }
|
||||
case FileSystem::EEncoding::UTF8: { FU8String Temp; if (!Temp.DecodeFrom(String)) return false; if (!FileSystem::SaveStringToFile(Temp, PathWithNull, FileSystem::EEncoding::UTF8, bWithBOM)) return false; break; }
|
||||
case FileSystem::EEncoding::UTF16BE: { FU16String Temp; if (!Temp.DecodeFrom(String)) return false; if (!FileSystem::SaveStringToFile(Temp, PathWithNull, FileSystem::EEncoding::UTF16BE, bWithBOM)) return false; break; }
|
||||
case FileSystem::EEncoding::UTF16LE: { FU16String Temp; if (!Temp.DecodeFrom(String)) return false; if (!FileSystem::SaveStringToFile(Temp, PathWithNull, FileSystem::EEncoding::UTF16LE, bWithBOM)) return false; break; }
|
||||
case FileSystem::EEncoding::UTF32BE: { FU32String Temp; if (!Temp.DecodeFrom(String)) return false; if (!FileSystem::SaveStringToFile(Temp, PathWithNull, FileSystem::EEncoding::UTF32BE, bWithBOM)) return false; break; }
|
||||
case FileSystem::EEncoding::UTF32LE: { FU32String Temp; if (!Temp.DecodeFrom(String)) return false; if (!FileSystem::SaveStringToFile(Temp, PathWithNull, FileSystem::EEncoding::UTF32LE, bWithBOM)) return false; break; }
|
||||
default: check_no_entry(); return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template REDCRAFTUTILITY_API bool SaveStringToFile<char> (FStringView, FStringView, FileSystem::EEncoding, bool);
|
||||
template REDCRAFTUTILITY_API bool SaveStringToFile<wchar> (FWStringView, FStringView, FileSystem::EEncoding, bool);
|
||||
template REDCRAFTUTILITY_API bool SaveStringToFile<u8char> (FU8StringView, FStringView, FileSystem::EEncoding, bool);
|
||||
template REDCRAFTUTILITY_API bool SaveStringToFile<u16char>(FU16StringView, FStringView, FileSystem::EEncoding, bool);
|
||||
template REDCRAFTUTILITY_API bool SaveStringToFile<u32char>(FU32StringView, FStringView, FileSystem::EEncoding, bool);
|
||||
|
||||
size_t FileSize(FStringView Path)
|
||||
{
|
||||
if (!FileSystem::Exists(Path)) return static_cast<size_t>(-1);
|
||||
|
||||
FILE* File = std::fopen(*Path, "rb");
|
||||
|
||||
if (File == nullptr) return static_cast<size_t>(-1);
|
||||
|
||||
auto FileGuard = TScopeCallback([=] { Ignore = std::fclose(File); });
|
||||
|
||||
if (std::fseek(File, 0, SEEK_END) != 0) return static_cast<size_t>(-1);
|
||||
|
||||
const long Length = std::ftell(File);
|
||||
|
||||
if (!Math::IsWithin(Length, 0, TNumericLimits<long>::Max())) return static_cast<size_t>(-1);
|
||||
|
||||
FileGuard.Release();
|
||||
|
||||
if (std::fclose(File) != 0) return static_cast<size_t>(-1);
|
||||
|
||||
return Length;
|
||||
}
|
||||
|
||||
bool Delete(FStringView Path)
|
||||
{
|
||||
return std::remove(*Path) == 0;
|
||||
}
|
||||
|
||||
bool Exists(FStringView Path)
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
DWORD Attributes = GetFileAttributesA(*Path);
|
||||
|
||||
if (Attributes == INVALID_FILE_ATTRIBUTES) return false;
|
||||
|
||||
return !(Attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
struct stat FileInfo;
|
||||
|
||||
FileInfo.st_size = -1;
|
||||
|
||||
if (stat(*Path, &FileInfo) != 0) return false;
|
||||
|
||||
if (!S_ISREG(FileInfo.st_mode)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
# endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Copy(FStringView Destination, FStringView Source)
|
||||
{
|
||||
if (!FileSystem::Exists(Source)) return false;
|
||||
|
||||
FILE* FileA = std::fopen(*Source, "rb");
|
||||
|
||||
if (FileA == nullptr) return false;
|
||||
|
||||
auto FileGuardA = TScopeCallback([=] { Ignore = std::fclose(FileA); });
|
||||
|
||||
FILE* FileB = std::fopen(*Destination, "wb");
|
||||
|
||||
if (FileB == nullptr) return false;
|
||||
|
||||
auto FileGuardB = TScopeCallback([=] { Ignore = std::fclose(FileB); });
|
||||
|
||||
size_t ReadSize;
|
||||
|
||||
constexpr size_t BufferSize = 4096;
|
||||
|
||||
TStaticArray<uint8, BufferSize> Buffer;
|
||||
|
||||
do
|
||||
{
|
||||
ReadSize = std::fread(Buffer.GetData(), 1, BufferSize, FileA);
|
||||
|
||||
if (std::fwrite(Buffer.GetData(), 1, ReadSize, FileB) != ReadSize) return false;
|
||||
}
|
||||
while (ReadSize == BufferSize);
|
||||
|
||||
FileGuardA.Release();
|
||||
|
||||
if (std::fclose(FileA) != 0) return false;
|
||||
|
||||
FileGuardB.Release();
|
||||
|
||||
if (std::fclose(FileB) != 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rename(FStringView Destination, FStringView Source)
|
||||
{
|
||||
return std::rename(*Source, *Destination) == 0;
|
||||
}
|
||||
|
||||
bool CreateDirectory(FStringView Path, bool bRecursive /* = false */)
|
||||
{
|
||||
if (Path.Num() == 0) return false;
|
||||
|
||||
if (bRecursive)
|
||||
{
|
||||
if (Path.Back() == '/' || Path.Back() == '\\') Path = Path.First(Path.Num() - 1);
|
||||
|
||||
FStringView Parent = Path.First(Path.FindLastOf("/\\"));
|
||||
|
||||
if (!FileSystem::ExistsDirectory(Parent) && !FileSystem::CreateDirectory(Parent, true)) return false;
|
||||
}
|
||||
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
return CreateDirectoryA(*Path, nullptr) != 0;
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
return mkdir(*Path, 0755) == 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeleteDirectory(FStringView Path, bool bRecursive /* = false */)
|
||||
{
|
||||
if (bRecursive)
|
||||
{
|
||||
FString Temp;
|
||||
|
||||
bool bSuccessfully = FileSystem::IterateDirectory(Path, [&](FStringView File, bool bIsDirectory) -> bool
|
||||
{
|
||||
Temp.Reset(false);
|
||||
|
||||
Temp += Path;
|
||||
Temp += '/';
|
||||
Temp += File;
|
||||
Temp += '\0';
|
||||
|
||||
if (bIsDirectory)
|
||||
{
|
||||
if (!FileSystem::DeleteDirectory(Temp, true)) return false;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!FileSystem::Delete(Temp)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!bSuccessfully) return false;
|
||||
}
|
||||
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
return RemoveDirectoryA(*Path) != 0;
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
return rmdir(*Path) == 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExistsDirectory(FStringView Path)
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
DWORD Attributes = GetFileAttributesA(*Path);
|
||||
|
||||
if (Attributes == INVALID_FILE_ATTRIBUTES) return false;
|
||||
|
||||
return Attributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
DIR* Directory = opendir(*Path);
|
||||
|
||||
if (Directory == nullptr) return false;
|
||||
|
||||
Ignore = closedir(Directory);
|
||||
|
||||
return true;
|
||||
}
|
||||
# endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IterateDirectory(FStringView Path, TFunctionRef<bool(FStringView /* Path */, bool /* bIsDirectory */)> Visitor)
|
||||
{
|
||||
# if PLATFORM_WINDOWS
|
||||
{
|
||||
FString FindPath;
|
||||
|
||||
FindPath.Reserve(Path.Num() + 3);
|
||||
|
||||
FindPath += Path;
|
||||
FindPath += '\\';
|
||||
FindPath += '*';
|
||||
FindPath += '\0';
|
||||
|
||||
WIN32_FIND_DATA FindData;
|
||||
|
||||
HANDLE FindHandle = FindFirstFileA(*FindPath, &FindData);
|
||||
|
||||
auto FindGuard = TScopeCallback([=] { Ignore = FindClose(FindHandle); });
|
||||
|
||||
if (FindHandle == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
do
|
||||
{
|
||||
const FStringView FilePath = FindData.cFileName;
|
||||
|
||||
if (FilePath == "." || FilePath == "..") continue;
|
||||
|
||||
const bool bIsDirectory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
|
||||
if (!Visitor(FilePath, bIsDirectory)) return false;
|
||||
}
|
||||
while (FindNextFileA(FindHandle, &FindData) != 0);
|
||||
|
||||
FindGuard.Release();
|
||||
|
||||
if (!FindClose(FindHandle)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
# elif PLATFORM_LINUX
|
||||
{
|
||||
DIR* Directory = opendir(*Path);
|
||||
|
||||
if (Directory == nullptr) return false;
|
||||
|
||||
auto DirectoryGuard = TScopeCallback([=] { Ignore = closedir(Directory); });
|
||||
|
||||
dirent* Entry;
|
||||
|
||||
while ((Entry = readdir(Directory)) != nullptr)
|
||||
{
|
||||
const FStringView FilePath = Entry->d_name;
|
||||
|
||||
if (FilePath == "." || FilePath == "..") continue;
|
||||
|
||||
const bool bIsDirectory = Entry->d_type == DT_DIR;
|
||||
|
||||
if (!Visitor(FilePath, bIsDirectory)) return false;
|
||||
}
|
||||
|
||||
DirectoryGuard.Release();
|
||||
|
||||
if (closedir(Directory) != 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
# endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NAMESPACE_END(FileSystem)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
||||
|
||||
#pragma warning(pop)
|
@ -1,4 +1,4 @@
|
||||
#include "Numeric/Random.h"
|
||||
#include "Numerics/Random.h"
|
||||
|
||||
#include "Templates/Atomic.h"
|
||||
|
368
Redcraft.Utility/Source/Private/Testing/Algorithms.cpp
Normal file
368
Redcraft.Utility/Source/Private/Testing/Algorithms.cpp
Normal file
@ -0,0 +1,368 @@
|
||||
#include "Testing/Testing.h"
|
||||
|
||||
#include "Algorithms/Algorithms.h"
|
||||
#include "Containers/Array.h"
|
||||
#include "Containers/List.h"
|
||||
#include "Ranges/Factory.h"
|
||||
#include "Numerics/Math.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
void TestBasic()
|
||||
{
|
||||
{
|
||||
TArray<int> Arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
auto Iter = Arr.Begin();
|
||||
|
||||
Algorithms::Advance(Iter, 5);
|
||||
|
||||
always_check(*Iter == 5);
|
||||
|
||||
always_check(Algorithms::Distance(Arr.Begin(), Iter) == 5);
|
||||
|
||||
always_check(Algorithms::Distance(Arr) == 10);
|
||||
|
||||
always_check(*Algorithms::Next(Iter) == 6);
|
||||
always_check(*Algorithms::Next(Iter, 2) == 7);
|
||||
always_check(*Algorithms::Prev(Iter) == 4);
|
||||
always_check(*Algorithms::Prev(Iter, 2) == 3);
|
||||
|
||||
always_check(Algorithms::Next(Iter, Arr.End()) == Arr.End());
|
||||
always_check(Algorithms::Next(Iter, 16, Arr.End()) == Arr.End());
|
||||
|
||||
always_check(Algorithms::Prev(Iter, 16, Arr.Begin()) == Arr.Begin());
|
||||
|
||||
Iter = Arr.Begin();
|
||||
|
||||
Algorithms::Advance(Iter, Arr.End());
|
||||
|
||||
always_check(Iter == Arr.End());
|
||||
|
||||
Iter = Arr.Begin();
|
||||
|
||||
always_check(Algorithms::Advance(Iter, 16, Arr.End()) == 6);
|
||||
|
||||
always_check(Iter == Arr.End());
|
||||
}
|
||||
|
||||
{
|
||||
TList<int> Arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
auto Iter = Arr.Begin();
|
||||
|
||||
Algorithms::Advance(Iter, 5);
|
||||
|
||||
always_check(*Iter == 5);
|
||||
|
||||
always_check(Algorithms::Distance(Arr.Begin(), Iter) == 5);
|
||||
|
||||
always_check(Algorithms::Distance(Arr) == 10);
|
||||
|
||||
always_check(*Algorithms::Next(Iter) == 6);
|
||||
always_check(*Algorithms::Next(Iter, 2) == 7);
|
||||
always_check(*Algorithms::Prev(Iter) == 4);
|
||||
always_check(*Algorithms::Prev(Iter, 2) == 3);
|
||||
|
||||
always_check(Algorithms::Next(Iter, Arr.End()) == Arr.End());
|
||||
always_check(Algorithms::Next(Iter, 16, Arr.End()) == Arr.End());
|
||||
|
||||
always_check(Algorithms::Prev(Iter, 16, Arr.Begin()) == Arr.Begin());
|
||||
|
||||
Iter = Arr.Begin();
|
||||
|
||||
Algorithms::Advance(Iter, Arr.End());
|
||||
|
||||
always_check(Iter == Arr.End());
|
||||
|
||||
Iter = Arr.Begin();
|
||||
|
||||
always_check(Algorithms::Advance(Iter, 16, Arr.End()) == 6);
|
||||
|
||||
always_check(Iter == Arr.End());
|
||||
}
|
||||
|
||||
{
|
||||
auto Arr = Ranges::Iota(0, 10);
|
||||
|
||||
auto Iter = Arr.Begin();
|
||||
|
||||
Algorithms::Advance(Iter, 5);
|
||||
|
||||
always_check(*Iter == 5);
|
||||
|
||||
always_check(Algorithms::Distance(Arr.Begin(), Iter) == 5);
|
||||
|
||||
always_check(Algorithms::Distance(Arr) == 10);
|
||||
|
||||
always_check(*Algorithms::Next(Iter) == 6);
|
||||
always_check(*Algorithms::Next(Iter, 2) == 7);
|
||||
|
||||
always_check(Algorithms::Next(Iter, Arr.End()) == Arr.End());
|
||||
always_check(Algorithms::Next(Iter, 16, Arr.End()) == Arr.End());
|
||||
|
||||
Iter = Arr.Begin();
|
||||
|
||||
Algorithms::Advance(Iter, Arr.End());
|
||||
|
||||
always_check(Iter == Arr.End());
|
||||
|
||||
Iter = Arr.Begin();
|
||||
|
||||
always_check(Algorithms::Advance(Iter, 16, Arr.End()) == 6);
|
||||
|
||||
always_check(Iter == Arr.End());
|
||||
}
|
||||
}
|
||||
|
||||
void TestSearch()
|
||||
{
|
||||
{
|
||||
TArray<int> Arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
TList<int> Brr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
auto Crr = Ranges::Iota(0, 10);
|
||||
|
||||
always_check( Algorithms::AllOf(Arr, [](int A) { return A < 10; }));
|
||||
always_check( Algorithms::AllOf(Brr, [](int A) { return A < 10; }));
|
||||
always_check( Algorithms::AllOf(Crr, [](int A) { return A < 10; }));
|
||||
always_check(!Algorithms::AllOf(Arr, [](int A) { return A > 5; }));
|
||||
always_check(!Algorithms::AllOf(Brr, [](int A) { return A > 5; }));
|
||||
always_check(!Algorithms::AllOf(Crr, [](int A) { return A > 5; }));
|
||||
|
||||
always_check( Algorithms::AllOf(Arr.Begin(), Arr.End(), [](int A) { return A < 10; }));
|
||||
always_check( Algorithms::AllOf(Brr.Begin(), Brr.End(), [](int A) { return A < 10; }));
|
||||
always_check( Algorithms::AllOf(Crr.Begin(), Crr.End(), [](int A) { return A < 10; }));
|
||||
always_check(!Algorithms::AllOf(Arr.Begin(), Arr.End(), [](int A) { return A > 5; }));
|
||||
always_check(!Algorithms::AllOf(Brr.Begin(), Brr.End(), [](int A) { return A > 5; }));
|
||||
always_check(!Algorithms::AllOf(Crr.Begin(), Crr.End(), [](int A) { return A > 5; }));
|
||||
|
||||
always_check(Algorithms::AnyOf(Arr, [](int A) { return A < 10; }));
|
||||
always_check(Algorithms::AnyOf(Brr, [](int A) { return A < 10; }));
|
||||
always_check(Algorithms::AnyOf(Crr, [](int A) { return A < 10; }));
|
||||
always_check(Algorithms::AnyOf(Arr, [](int A) { return A > 5; }));
|
||||
always_check(Algorithms::AnyOf(Brr, [](int A) { return A > 5; }));
|
||||
always_check(Algorithms::AnyOf(Crr, [](int A) { return A > 5; }));
|
||||
|
||||
always_check(Algorithms::AnyOf(Arr.Begin(), Arr.End(), [](int A) { return A < 10; }));
|
||||
always_check(Algorithms::AnyOf(Brr.Begin(), Brr.End(), [](int A) { return A < 10; }));
|
||||
always_check(Algorithms::AnyOf(Crr.Begin(), Crr.End(), [](int A) { return A < 10; }));
|
||||
always_check(Algorithms::AnyOf(Arr.Begin(), Arr.End(), [](int A) { return A > 5; }));
|
||||
always_check(Algorithms::AnyOf(Brr.Begin(), Brr.End(), [](int A) { return A > 5; }));
|
||||
always_check(Algorithms::AnyOf(Crr.Begin(), Crr.End(), [](int A) { return A > 5; }));
|
||||
|
||||
always_check(!Algorithms::NoneOf(Arr, [](int A) { return A < 10; }));
|
||||
always_check(!Algorithms::NoneOf(Brr, [](int A) { return A < 10; }));
|
||||
always_check(!Algorithms::NoneOf(Crr, [](int A) { return A < 10; }));
|
||||
always_check(!Algorithms::NoneOf(Arr, [](int A) { return A > 5; }));
|
||||
always_check(!Algorithms::NoneOf(Brr, [](int A) { return A > 5; }));
|
||||
always_check(!Algorithms::NoneOf(Crr, [](int A) { return A > 5; }));
|
||||
|
||||
always_check(!Algorithms::NoneOf(Arr.Begin(), Arr.End(), [](int A) { return A < 10; }));
|
||||
always_check(!Algorithms::NoneOf(Brr.Begin(), Brr.End(), [](int A) { return A < 10; }));
|
||||
always_check(!Algorithms::NoneOf(Crr.Begin(), Crr.End(), [](int A) { return A < 10; }));
|
||||
always_check(!Algorithms::NoneOf(Arr.Begin(), Arr.End(), [](int A) { return A > 5; }));
|
||||
always_check(!Algorithms::NoneOf(Brr.Begin(), Brr.End(), [](int A) { return A > 5; }));
|
||||
always_check(!Algorithms::NoneOf(Crr.Begin(), Crr.End(), [](int A) { return A > 5; }));
|
||||
|
||||
always_check( Algorithms::Contains(Arr, 5));
|
||||
always_check( Algorithms::Contains(Brr, 5));
|
||||
always_check( Algorithms::Contains(Crr, 5));
|
||||
always_check(!Algorithms::Contains(Arr, 10));
|
||||
always_check(!Algorithms::Contains(Brr, 10));
|
||||
always_check(!Algorithms::Contains(Crr, 10));
|
||||
|
||||
always_check( Algorithms::Contains(Arr.Begin(), Arr.End(), 5));
|
||||
always_check( Algorithms::Contains(Brr.Begin(), Brr.End(), 5));
|
||||
always_check( Algorithms::Contains(Crr.Begin(), Crr.End(), 5));
|
||||
always_check(!Algorithms::Contains(Arr.Begin(), Arr.End(), 10));
|
||||
always_check(!Algorithms::Contains(Brr.Begin(), Brr.End(), 10));
|
||||
always_check(!Algorithms::Contains(Crr.Begin(), Crr.End(), 10));
|
||||
|
||||
auto Projection = [](int A) { return A % 4; }; // Project to { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1 }
|
||||
|
||||
always_check(Algorithms::Find(Arr, 2, { }, Projection) == Algorithms::Next(Arr.Begin(), 2));
|
||||
always_check(Algorithms::Find(Brr, 2, { }, Projection) == Algorithms::Next(Brr.Begin(), 2));
|
||||
always_check(Algorithms::Find(Crr, 2, { }, Projection) == Algorithms::Next(Crr.Begin(), 2));
|
||||
|
||||
always_check(Algorithms::Find(Arr.Begin(), Arr.End(), 2, { }, Projection) == Algorithms::Next(Arr.Begin(), 2));
|
||||
always_check(Algorithms::Find(Brr.Begin(), Brr.End(), 2, { }, Projection) == Algorithms::Next(Brr.Begin(), 2));
|
||||
always_check(Algorithms::Find(Crr.Begin(), Crr.End(), 2, { }, Projection) == Algorithms::Next(Crr.Begin(), 2));
|
||||
|
||||
always_check(Algorithms::Find(Arr, 10) == Arr.End());
|
||||
always_check(Algorithms::Find(Brr, 10) == Brr.End());
|
||||
always_check(Algorithms::Find(Crr, 10) == Crr.End());
|
||||
|
||||
always_check(Algorithms::Find(Arr, Ranges::Iota(1, 4), { }, Projection).Begin() == Algorithms::Next(Arr.Begin()));
|
||||
always_check(Algorithms::Find(Brr, Ranges::Iota(1, 4), { }, Projection).Begin() == Algorithms::Next(Brr.Begin()));
|
||||
always_check(Algorithms::Find(Crr, Ranges::Iota(1, 4), { }, Projection).Begin() == Algorithms::Next(Crr.Begin()));
|
||||
|
||||
always_check(Algorithms::Find(Arr, Ranges::Iota(4, 16)).IsEmpty());
|
||||
always_check(Algorithms::Find(Brr, Ranges::Iota(4, 16)).IsEmpty());
|
||||
always_check(Algorithms::Find(Crr, Ranges::Iota(4, 16)).IsEmpty());
|
||||
|
||||
always_check(Algorithms::FindIf(Arr, [](int A) { return A == 2; }, Projection) == Algorithms::Next(Arr.Begin(), 2));
|
||||
always_check(Algorithms::FindIf(Brr, [](int A) { return A == 2; }, Projection) == Algorithms::Next(Brr.Begin(), 2));
|
||||
always_check(Algorithms::FindIf(Crr, [](int A) { return A == 2; }, Projection) == Algorithms::Next(Crr.Begin(), 2));
|
||||
|
||||
always_check(Algorithms::FindIf(Arr.Begin(), Arr.End(), [](int A) { return A == 2; }, Projection) == Algorithms::Next(Arr.Begin(), 2));
|
||||
always_check(Algorithms::FindIf(Brr.Begin(), Brr.End(), [](int A) { return A == 2; }, Projection) == Algorithms::Next(Brr.Begin(), 2));
|
||||
always_check(Algorithms::FindIf(Crr.Begin(), Crr.End(), [](int A) { return A == 2; }, Projection) == Algorithms::Next(Crr.Begin(), 2));
|
||||
|
||||
always_check(Algorithms::FindIf(Arr, [](int A) { return A == 10; }) == Arr.End());
|
||||
always_check(Algorithms::FindIf(Brr, [](int A) { return A == 10; }) == Brr.End());
|
||||
always_check(Algorithms::FindIf(Crr, [](int A) { return A == 10; }) == Crr.End());
|
||||
|
||||
always_check(Algorithms::FindIfNot(Arr, [](int A) { return A > 0; }, Projection) == Arr.Begin());
|
||||
always_check(Algorithms::FindIfNot(Brr, [](int A) { return A > 0; }, Projection) == Brr.Begin());
|
||||
always_check(Algorithms::FindIfNot(Crr, [](int A) { return A > 0; }, Projection) == Crr.Begin());
|
||||
|
||||
always_check(Algorithms::FindIfNot(Arr.Begin(), Arr.End(), [](int A) { return A > 0; }, Projection) == Arr.Begin());
|
||||
always_check(Algorithms::FindIfNot(Brr.Begin(), Brr.End(), [](int A) { return A > 0; }, Projection) == Brr.Begin());
|
||||
always_check(Algorithms::FindIfNot(Crr.Begin(), Crr.End(), [](int A) { return A > 0; }, Projection) == Crr.Begin());
|
||||
|
||||
always_check(Algorithms::FindIfNot(Arr, [](int A) { return A < 8; }) == Algorithms::Next(Arr.Begin(), 8));
|
||||
always_check(Algorithms::FindIfNot(Brr, [](int A) { return A < 8; }) == Algorithms::Next(Brr.Begin(), 8));
|
||||
always_check(Algorithms::FindIfNot(Crr, [](int A) { return A < 8; }) == Algorithms::Next(Crr.Begin(), 8));
|
||||
|
||||
always_check(Algorithms::FindLast(Arr, 2, { }, Projection) == Algorithms::Next(Arr.Begin(), 6));
|
||||
always_check(Algorithms::FindLast(Brr, 2, { }, Projection) == Algorithms::Next(Brr.Begin(), 6));
|
||||
always_check(Algorithms::FindLast(Crr, 2, { }, Projection) == Algorithms::Next(Crr.Begin(), 6));
|
||||
|
||||
always_check(Algorithms::FindLast(Arr.Begin(), Arr.End(), 2, { }, Projection) == Algorithms::Next(Arr.Begin(), 6));
|
||||
always_check(Algorithms::FindLast(Brr.Begin(), Brr.End(), 2, { }, Projection) == Algorithms::Next(Brr.Begin(), 6));
|
||||
always_check(Algorithms::FindLast(Crr.Begin(), Crr.End(), 2, { }, Projection) == Algorithms::Next(Crr.Begin(), 6));
|
||||
|
||||
always_check(Algorithms::FindLast(Arr, 10) == Arr.End());
|
||||
always_check(Algorithms::FindLast(Brr, 10) == Brr.End());
|
||||
always_check(Algorithms::FindLast(Crr, 10) == Crr.End());
|
||||
|
||||
always_check(Algorithms::FindLast(Arr, Ranges::Iota(1, 4), { }, Projection).Begin() == Algorithms::Next(Arr.Begin(), 5));
|
||||
always_check(Algorithms::FindLast(Brr, Ranges::Iota(1, 4), { }, Projection).Begin() == Algorithms::Next(Brr.Begin(), 5));
|
||||
always_check(Algorithms::FindLast(Crr, Ranges::Iota(1, 4), { }, Projection).Begin() == Algorithms::Next(Crr.Begin(), 5));
|
||||
|
||||
always_check(Algorithms::FindLast(Arr, Ranges::Iota(4, 16)).IsEmpty());
|
||||
always_check(Algorithms::FindLast(Brr, Ranges::Iota(4, 16)).IsEmpty());
|
||||
always_check(Algorithms::FindLast(Crr, Ranges::Iota(4, 16)).IsEmpty());
|
||||
|
||||
always_check(Algorithms::FindLastIf(Arr, [](int A) { return A == 2; }, Projection) == Algorithms::Next(Arr.Begin(), 6));
|
||||
always_check(Algorithms::FindLastIf(Brr, [](int A) { return A == 2; }, Projection) == Algorithms::Next(Brr.Begin(), 6));
|
||||
always_check(Algorithms::FindLastIf(Crr, [](int A) { return A == 2; }, Projection) == Algorithms::Next(Crr.Begin(), 6));
|
||||
|
||||
always_check(Algorithms::FindLastIf(Arr.Begin(), Arr.End(), [](int A) { return A == 2; }, Projection) == Algorithms::Next(Arr.Begin(), 6));
|
||||
always_check(Algorithms::FindLastIf(Brr.Begin(), Brr.End(), [](int A) { return A == 2; }, Projection) == Algorithms::Next(Brr.Begin(), 6));
|
||||
always_check(Algorithms::FindLastIf(Crr.Begin(), Crr.End(), [](int A) { return A == 2; }, Projection) == Algorithms::Next(Crr.Begin(), 6));
|
||||
|
||||
always_check(Algorithms::FindLastIf(Arr, [](int A) { return A == 10; }) == Arr.End());
|
||||
always_check(Algorithms::FindLastIf(Brr, [](int A) { return A == 10; }) == Brr.End());
|
||||
always_check(Algorithms::FindLastIf(Crr, [](int A) { return A == 10; }) == Crr.End());
|
||||
|
||||
always_check(Algorithms::FindLastIfNot(Arr, [](int A) { return A > 0; }, Projection) == Algorithms::Next(Arr.Begin(), 8));
|
||||
always_check(Algorithms::FindLastIfNot(Brr, [](int A) { return A > 0; }, Projection) == Algorithms::Next(Brr.Begin(), 8));
|
||||
always_check(Algorithms::FindLastIfNot(Crr, [](int A) { return A > 0; }, Projection) == Algorithms::Next(Crr.Begin(), 8));
|
||||
|
||||
always_check(Algorithms::FindLastIfNot(Arr.Begin(), Arr.End(), [](int A) { return A > 0; }, Projection) == Algorithms::Next(Arr.Begin(), 8));
|
||||
always_check(Algorithms::FindLastIfNot(Brr.Begin(), Brr.End(), [](int A) { return A > 0; }, Projection) == Algorithms::Next(Brr.Begin(), 8));
|
||||
always_check(Algorithms::FindLastIfNot(Crr.Begin(), Crr.End(), [](int A) { return A > 0; }, Projection) == Algorithms::Next(Crr.Begin(), 8));
|
||||
|
||||
always_check(Algorithms::FindLastIfNot(Arr, [](int A) { return A < 8; }) == Algorithms::Next(Arr.Begin(), 9));
|
||||
always_check(Algorithms::FindLastIfNot(Brr, [](int A) { return A < 8; }) == Algorithms::Next(Brr.Begin(), 9));
|
||||
always_check(Algorithms::FindLastIfNot(Crr, [](int A) { return A < 8; }) == Algorithms::Next(Crr.Begin(), 9));
|
||||
|
||||
always_check(Algorithms::FindAdjacent(Arr, { }, [](int A) { return Math::DivAndCeil(A, 2); }) == Algorithms::Next(Arr.Begin()));
|
||||
always_check(Algorithms::FindAdjacent(Brr, { }, [](int A) { return Math::DivAndCeil(A, 2); }) == Algorithms::Next(Brr.Begin()));
|
||||
always_check(Algorithms::FindAdjacent(Crr, { }, [](int A) { return Math::DivAndCeil(A, 2); }) == Algorithms::Next(Crr.Begin()));
|
||||
|
||||
always_check(Algorithms::FindAdjacent(Arr.Begin(), Arr.End(), { }, [](int A) { return Math::DivAndCeil(A, 2); }) == Algorithms::Next(Arr.Begin()));
|
||||
always_check(Algorithms::FindAdjacent(Brr.Begin(), Brr.End(), { }, [](int A) { return Math::DivAndCeil(A, 2); }) == Algorithms::Next(Brr.Begin()));
|
||||
always_check(Algorithms::FindAdjacent(Crr.Begin(), Crr.End(), { }, [](int A) { return Math::DivAndCeil(A, 2); }) == Algorithms::Next(Crr.Begin()));
|
||||
|
||||
always_check(Algorithms::FindAdjacent(Arr) == Arr.End());
|
||||
always_check(Algorithms::FindAdjacent(Brr) == Brr.End());
|
||||
always_check(Algorithms::FindAdjacent(Crr) == Crr.End());
|
||||
|
||||
always_check(Algorithms::Count(Arr, 2, { }, Projection) == 2);
|
||||
always_check(Algorithms::Count(Brr, 2, { }, Projection) == 2);
|
||||
always_check(Algorithms::Count(Crr, 2, { }, Projection) == 2);
|
||||
|
||||
always_check(Algorithms::Count(Arr.Begin(), Arr.End(), 2, { }, Projection) == 2);
|
||||
always_check(Algorithms::Count(Brr.Begin(), Brr.End(), 2, { }, Projection) == 2);
|
||||
always_check(Algorithms::Count(Crr.Begin(), Crr.End(), 2, { }, Projection) == 2);
|
||||
|
||||
always_check(Algorithms::Count(Arr, 10) == 0);
|
||||
always_check(Algorithms::Count(Brr, 10) == 0);
|
||||
always_check(Algorithms::Count(Crr, 10) == 0);
|
||||
|
||||
always_check(Algorithms::CountIf(Arr, [](int A) { return A == 2; }, Projection) == 2);
|
||||
always_check(Algorithms::CountIf(Brr, [](int A) { return A == 2; }, Projection) == 2);
|
||||
always_check(Algorithms::CountIf(Crr, [](int A) { return A == 2; }, Projection) == 2);
|
||||
|
||||
always_check(Algorithms::CountIf(Arr.Begin(), Arr.End(), [](int A) { return A == 2; }, Projection) == 2);
|
||||
always_check(Algorithms::CountIf(Brr.Begin(), Brr.End(), [](int A) { return A == 2; }, Projection) == 2);
|
||||
always_check(Algorithms::CountIf(Crr.Begin(), Crr.End(), [](int A) { return A == 2; }, Projection) == 2);
|
||||
|
||||
always_check(Algorithms::CountIf(Arr, [](int A) { return A == 10; }) == 0);
|
||||
always_check(Algorithms::CountIf(Brr, [](int A) { return A == 10; }) == 0);
|
||||
always_check(Algorithms::CountIf(Crr, [](int A) { return A == 10; }) == 0);
|
||||
|
||||
always_check(Algorithms::Mismatch(Arr, Arr, { }, Projection) == MakeTuple(Algorithms::Next(Arr.Begin(), 4), Algorithms::Next(Arr.Begin(), 4)));
|
||||
always_check(Algorithms::Mismatch(Brr, Brr, { }, Projection) == MakeTuple(Algorithms::Next(Brr.Begin(), 4), Algorithms::Next(Brr.Begin(), 4)));
|
||||
always_check(Algorithms::Mismatch(Crr, Crr, { }, Projection) == MakeTuple(Algorithms::Next(Crr.Begin(), 4), Algorithms::Next(Crr.Begin(), 4)));
|
||||
|
||||
always_check(Algorithms::Mismatch(Arr.Begin(), Arr.End(), Brr.Begin(), Brr.End(), { }, Projection) == MakeTuple(Algorithms::Next(Arr.Begin(), 4), Algorithms::Next(Brr.Begin(), 4)));
|
||||
always_check(Algorithms::Mismatch(Brr.Begin(), Brr.End(), Crr.Begin(), Crr.End(), { }, Projection) == MakeTuple(Algorithms::Next(Brr.Begin(), 4), Algorithms::Next(Crr.Begin(), 4)));
|
||||
always_check(Algorithms::Mismatch(Crr.Begin(), Crr.End(), Arr.Begin(), Arr.End(), { }, Projection) == MakeTuple(Algorithms::Next(Crr.Begin(), 4), Algorithms::Next(Arr.Begin(), 4)));
|
||||
|
||||
always_check(Algorithms::Mismatch(Arr, Brr, { }, Projection) == MakeTuple(Algorithms::Next(Arr.Begin(), 4), Algorithms::Next(Brr.Begin(), 4)));
|
||||
always_check(Algorithms::Mismatch(Brr, Crr, { }, Projection) == MakeTuple(Algorithms::Next(Brr.Begin(), 4), Algorithms::Next(Crr.Begin(), 4)));
|
||||
always_check(Algorithms::Mismatch(Crr, Arr, { }, Projection) == MakeTuple(Algorithms::Next(Crr.Begin(), 4), Algorithms::Next(Arr.Begin(), 4)));
|
||||
|
||||
always_check(Algorithms::Equal(Arr, Arr));
|
||||
always_check(Algorithms::Equal(Brr, Brr));
|
||||
always_check(Algorithms::Equal(Crr, Crr));
|
||||
|
||||
always_check(Algorithms::Equal(Arr.Begin(), Arr.End(), Brr.Begin(), Brr.End()));
|
||||
always_check(Algorithms::Equal(Brr.Begin(), Brr.End(), Crr.Begin(), Crr.End()));
|
||||
always_check(Algorithms::Equal(Crr.Begin(), Crr.End(), Arr.Begin(), Arr.End()));
|
||||
|
||||
always_check(Algorithms::Equal(Arr, Brr));
|
||||
always_check(Algorithms::Equal(Brr, Crr));
|
||||
always_check(Algorithms::Equal(Crr, Arr));
|
||||
|
||||
always_check(Algorithms::StartsWith(Arr, Ranges::Iota(0, 8)));
|
||||
always_check(Algorithms::StartsWith(Brr, Ranges::Iota(0, 8)));
|
||||
always_check(Algorithms::StartsWith(Crr, Ranges::Iota(0, 8)));
|
||||
|
||||
always_check(!Algorithms::StartsWith(Arr, Ranges::Iota(0, 8), { }, Projection));
|
||||
always_check(!Algorithms::StartsWith(Brr, Ranges::Iota(0, 8), { }, Projection));
|
||||
always_check(!Algorithms::StartsWith(Crr, Ranges::Iota(0, 8), { }, Projection));
|
||||
|
||||
always_check(Algorithms::EndsWith(Arr, Ranges::Iota(8, 10)));
|
||||
always_check(Algorithms::EndsWith(Brr, Ranges::Iota(8, 10)));
|
||||
always_check(Algorithms::EndsWith(Crr, Ranges::Iota(8, 10)));
|
||||
|
||||
always_check(Algorithms::EndsWith(Arr, Ranges::Iota(0, 2), { }, Projection));
|
||||
always_check(Algorithms::EndsWith(Brr, Ranges::Iota(0, 2), { }, Projection));
|
||||
always_check(Algorithms::EndsWith(Crr, Ranges::Iota(0, 2), { }, Projection));
|
||||
}
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
void TestAlgorithms()
|
||||
{
|
||||
NAMESPACE_PRIVATE::TestBasic();
|
||||
NAMESPACE_PRIVATE::TestSearch();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,4 +1,4 @@
|
||||
#include "Testing/ContainersTesting.h"
|
||||
#include "Testing/Testing.h"
|
||||
|
||||
#include "Containers/Containers.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
@ -11,15 +11,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
void TestContainers()
|
||||
{
|
||||
TestArray();
|
||||
TestStaticArray();
|
||||
TestArrayView();
|
||||
TestBitset();
|
||||
TestStaticBitset();
|
||||
TestList();
|
||||
}
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
NAMESPACE_UNNAMED_BEGIN
|
||||
|
||||
@ -603,6 +595,18 @@ void TestList()
|
||||
}
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
void TestContainers()
|
||||
{
|
||||
NAMESPACE_PRIVATE::TestArray();
|
||||
NAMESPACE_PRIVATE::TestStaticArray();
|
||||
NAMESPACE_PRIVATE::TestArrayView();
|
||||
NAMESPACE_PRIVATE::TestBitset();
|
||||
NAMESPACE_PRIVATE::TestStaticBitset();
|
||||
NAMESPACE_PRIVATE::TestList();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
// ReSharper restore CppInconsistentNaming
|
230
Redcraft.Utility/Source/Private/Testing/Iterators.cpp
Normal file
230
Redcraft.Utility/Source/Private/Testing/Iterators.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#include "Testing/Testing.h"
|
||||
|
||||
#include "Iterators/Iterators.h"
|
||||
#include "Containers/List.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
void TestMoveIterator()
|
||||
{
|
||||
{
|
||||
struct FTracker
|
||||
{
|
||||
FTracker() = default;
|
||||
FTracker(const FTracker&) { always_check_no_entry(); }
|
||||
FTracker(FTracker&&) = default;
|
||||
~FTracker() = default;
|
||||
FTracker& operator=(const FTracker&) { always_check_no_entry(); }
|
||||
FTracker& operator=(FTracker&&) = default;
|
||||
};
|
||||
|
||||
FTracker Arr[2];
|
||||
|
||||
auto First = MakeMoveIterator(&Arr[0]);
|
||||
auto Last = MakeMoveIterator(&Arr[2]);
|
||||
|
||||
FTracker Temp(*First++);
|
||||
|
||||
Temp = *First++;
|
||||
|
||||
always_check(First == Last);
|
||||
}
|
||||
|
||||
{
|
||||
int Arr[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
auto First = MakeMoveIterator(&Arr[0]);
|
||||
auto Last = MakeMoveIterator(&Arr[8]);
|
||||
|
||||
auto ConstFirst = MakeMoveIterator(&AsConst(Arr)[0]);
|
||||
auto ConstLast = MakeMoveIterator(&AsConst(Arr)[8]);
|
||||
|
||||
always_check(First == ConstFirst);
|
||||
always_check(Last == ConstLast );
|
||||
|
||||
always_check(ConstLast - First == 8);
|
||||
|
||||
auto Iter = ConstFirst;
|
||||
auto Jter = ConstLast;
|
||||
|
||||
++Iter;
|
||||
--Jter;
|
||||
|
||||
always_check(*Iter++ == 1);
|
||||
always_check(*Jter-- == 7);
|
||||
|
||||
Iter += 2;
|
||||
Jter -= 2;
|
||||
|
||||
always_check(Iter[-1] == 3);
|
||||
always_check(Jter[ 1] == 5);
|
||||
|
||||
Iter = Iter - 2;
|
||||
Jter = Jter + 2;
|
||||
|
||||
always_check(*Iter == 2);
|
||||
always_check(*Jter == 6);
|
||||
|
||||
Iter = 2 + Iter;
|
||||
Jter = Jter - 2;
|
||||
|
||||
always_check(Iter - Jter == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void TestReverseIterator()
|
||||
{
|
||||
int Arr[8] = { 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||
|
||||
auto First = MakeReverseIterator(&Arr[8]);
|
||||
auto Last = MakeReverseIterator(&Arr[0]);
|
||||
|
||||
auto ConstFirst = MakeReverseIterator(&AsConst(Arr)[8]);
|
||||
auto ConstLast = MakeReverseIterator(&AsConst(Arr)[0]);
|
||||
|
||||
always_check(First == ConstFirst);
|
||||
always_check(Last == ConstLast );
|
||||
|
||||
always_check(ConstLast - First == 8);
|
||||
|
||||
auto Iter = ConstFirst;
|
||||
auto Jter = ConstLast;
|
||||
|
||||
++Iter;
|
||||
--Jter;
|
||||
|
||||
always_check(*Iter++ == 1);
|
||||
always_check(*Jter-- == 7);
|
||||
|
||||
Iter += 2;
|
||||
Jter -= 2;
|
||||
|
||||
always_check(Iter[-1] == 3);
|
||||
always_check(Jter[ 1] == 5);
|
||||
|
||||
Iter = Iter - 2;
|
||||
Jter = Jter + 2;
|
||||
|
||||
always_check(*Iter == 2);
|
||||
always_check(*Jter == 6);
|
||||
|
||||
Iter = 2 + Iter;
|
||||
Jter = Jter - 2;
|
||||
|
||||
always_check(Iter - Jter == 0);
|
||||
}
|
||||
|
||||
void TestCountedIterator()
|
||||
{
|
||||
int Arr[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
auto First = MakeCountedIterator(&Arr[0], 8);
|
||||
auto Last = First + 8;
|
||||
|
||||
auto ConstFirst = MakeCountedIterator(&AsConst(Arr)[0], 8);
|
||||
auto ConstLast = ConstFirst + 8;
|
||||
|
||||
always_check(First == ConstFirst);
|
||||
always_check(Last == ConstLast );
|
||||
|
||||
always_check(ConstLast - First == 8);
|
||||
|
||||
always_check(Last == DefaultSentinel);
|
||||
always_check(DefaultSentinel == Last);
|
||||
|
||||
always_check(DefaultSentinel - First == 8);
|
||||
always_check(First - DefaultSentinel == -8);
|
||||
|
||||
always_check(First == ConstFirst);
|
||||
always_check(Last == ConstLast );
|
||||
|
||||
always_check(Last - First == 8);
|
||||
|
||||
auto Iter = ConstFirst;
|
||||
auto Jter = ConstLast;
|
||||
|
||||
++Iter;
|
||||
--Jter;
|
||||
|
||||
always_check(*Iter++ == 1);
|
||||
always_check(*Jter-- == 7);
|
||||
|
||||
Iter += 2;
|
||||
Jter -= 2;
|
||||
|
||||
always_check(Iter[-1] == 3);
|
||||
always_check(Jter[ 1] == 5);
|
||||
|
||||
Iter = Iter - 2;
|
||||
Jter = Jter + 2;
|
||||
|
||||
always_check(*Iter == 2);
|
||||
always_check(*Jter == 6);
|
||||
|
||||
Iter = 2 + Iter;
|
||||
Jter = Jter - 2;
|
||||
|
||||
always_check(Iter - Jter == 0);
|
||||
}
|
||||
|
||||
void TestInsertIterator()
|
||||
{
|
||||
{
|
||||
TList<int> List = { 1, 2, 3 };
|
||||
|
||||
auto Iter = MakeFrontInserter(List);
|
||||
|
||||
*Iter++ = 1;
|
||||
*Iter++ = 2;
|
||||
*Iter++ = 3;
|
||||
|
||||
always_check(List == TList<int>({ 3, 2, 1, 1, 2, 3 }));
|
||||
}
|
||||
|
||||
{
|
||||
TList<int> List = { 1, 2, 3 };
|
||||
|
||||
auto Iter = MakeBackInserter(List);
|
||||
|
||||
*Iter++ = 1;
|
||||
*Iter++ = 2;
|
||||
*Iter++ = 3;
|
||||
|
||||
always_check(List == TList<int>({ 1, 2, 3, 1, 2, 3 }));
|
||||
}
|
||||
|
||||
{
|
||||
TList<int> List = { 1, 2, 3 };
|
||||
|
||||
auto Iter = MakeInserter(List, ++++List.Begin());
|
||||
|
||||
*Iter++ = 1;
|
||||
*Iter++ = 2;
|
||||
*Iter++ = 3;
|
||||
|
||||
always_check(List == TList<int>({ 1, 2, 1, 2, 3, 3 }));
|
||||
}
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
void TestIterator()
|
||||
{
|
||||
NAMESPACE_PRIVATE::TestMoveIterator();
|
||||
NAMESPACE_PRIVATE::TestReverseIterator();
|
||||
NAMESPACE_PRIVATE::TestCountedIterator();
|
||||
NAMESPACE_PRIVATE::TestInsertIterator();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,4 +1,4 @@
|
||||
#include "Testing/MemoryTesting.h"
|
||||
#include "Testing/Testing.h"
|
||||
|
||||
#include "Memory/Memory.h"
|
||||
#include "Memory/Alignment.h"
|
||||
@ -15,18 +15,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
void TestMemory()
|
||||
{
|
||||
TestAddress();
|
||||
TestAlignment();
|
||||
TestMemoryBuffer();
|
||||
TestMemoryMalloc();
|
||||
TestMemoryOperator();
|
||||
TestPointerTraits();
|
||||
TestUniquePointer();
|
||||
TestSharedPointer();
|
||||
TestInOutPointer();
|
||||
}
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
NAMESPACE_UNNAMED_BEGIN
|
||||
|
||||
@ -1072,6 +1061,21 @@ void TestInOutPointer()
|
||||
}
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
void TestMemory()
|
||||
{
|
||||
NAMESPACE_PRIVATE::TestAddress();
|
||||
NAMESPACE_PRIVATE::TestAlignment();
|
||||
NAMESPACE_PRIVATE::TestMemoryBuffer();
|
||||
NAMESPACE_PRIVATE::TestMemoryMalloc();
|
||||
NAMESPACE_PRIVATE::TestMemoryOperator();
|
||||
NAMESPACE_PRIVATE::TestPointerTraits();
|
||||
NAMESPACE_PRIVATE::TestUniquePointer();
|
||||
NAMESPACE_PRIVATE::TestSharedPointer();
|
||||
NAMESPACE_PRIVATE::TestInOutPointer();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
@ -1,4 +1,4 @@
|
||||
#include "Testing/MiscellaneousTesting.h"
|
||||
#include "Testing/Testing.h"
|
||||
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
@ -10,12 +10,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
void TestMiscellaneous()
|
||||
{
|
||||
TestAssertionMacros();
|
||||
TestCompare();
|
||||
TestVarArgs();
|
||||
}
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
NAMESPACE_UNNAMED_BEGIN
|
||||
|
||||
@ -127,7 +122,7 @@ void TestCompare()
|
||||
always_check(( 0 <=> 0) == strong_ordering::equivalent);
|
||||
always_check(( 0 <=> 0) == strong_ordering::equal);
|
||||
always_check(( 0 <=> -1) == strong_ordering::greater);
|
||||
|
||||
|
||||
always_check((-1 <=> 0) < 0);
|
||||
always_check((-1 <=> 0) <= 0);
|
||||
always_check(( 0 <=> 0) <= 0);
|
||||
@ -148,12 +143,12 @@ void TestCompare()
|
||||
always_check((-1.0 <=> 0.0) == weak_ordering::less);
|
||||
always_check(( 0.0 <=> 0.0) == weak_ordering::equivalent);
|
||||
always_check(( 0.0 <=> -1.0) == weak_ordering::greater);
|
||||
|
||||
|
||||
always_check((-1.0 <=> 0.0) == strong_ordering::less);
|
||||
always_check(( 0.0 <=> 0.0) == strong_ordering::equivalent);
|
||||
always_check(( 0.0 <=> 0.0) == strong_ordering::equal);
|
||||
always_check(( 0.0 <=> -1.0) == strong_ordering::greater);
|
||||
|
||||
|
||||
always_check((-1.0 <=> 0.0) < 0);
|
||||
always_check((-1.0 <=> 0.0) <= 0);
|
||||
always_check(( 0.0 <=> 0.0) <= 0);
|
||||
@ -162,26 +157,26 @@ void TestCompare()
|
||||
always_check(( 0.0 <=> -1.0) >= 0);
|
||||
always_check(( 0.0 <=> -1.0) > 0);
|
||||
always_check((-1.0 <=> 1.0) != 0);
|
||||
|
||||
|
||||
always_check((FTestPartialOrdering(-1) <=> FTestPartialOrdering( 0)) == partial_ordering::less);
|
||||
always_check((FTestPartialOrdering( 0) <=> FTestPartialOrdering( 0)) == partial_ordering::equivalent);
|
||||
always_check((FTestPartialOrdering( 0) <=> FTestPartialOrdering(-1)) == partial_ordering::greater);
|
||||
|
||||
always_check((FTestPartialOrdering( 0, true) <=> FTestPartialOrdering( 0, false)) == partial_ordering::unordered);
|
||||
|
||||
|
||||
always_check((FTestWeakOrdering(-1) <=> FTestWeakOrdering( 0)) == weak_ordering::less);
|
||||
always_check((FTestWeakOrdering( 0) <=> FTestWeakOrdering( 0)) == weak_ordering::equivalent);
|
||||
always_check((FTestWeakOrdering( 0) <=> FTestWeakOrdering(-1)) == weak_ordering::greater);
|
||||
|
||||
|
||||
always_check((FTestStrongOrdering(-1) <=> FTestStrongOrdering( 0)) == strong_ordering::less);
|
||||
always_check((FTestStrongOrdering( 0) <=> FTestStrongOrdering( 0)) == strong_ordering::equivalent);
|
||||
always_check((FTestStrongOrdering( 0) <=> FTestStrongOrdering( 0)) == strong_ordering::equal);
|
||||
always_check((FTestStrongOrdering( 0) <=> FTestStrongOrdering(-1)) == strong_ordering::greater);
|
||||
|
||||
|
||||
always_check((FTestPartialOrdering(-1) < FTestPartialOrdering( 0)));
|
||||
always_check((FTestPartialOrdering( 0) == FTestPartialOrdering( 0)));
|
||||
always_check((FTestPartialOrdering( 0) > FTestPartialOrdering(-1)));
|
||||
|
||||
|
||||
always_check((FTestWeakOrdering(-1) < FTestWeakOrdering( 0)));
|
||||
always_check((FTestWeakOrdering( 0) == FTestWeakOrdering( 0)));
|
||||
always_check((FTestWeakOrdering( 0) > FTestWeakOrdering(-1)));
|
||||
@ -216,7 +211,7 @@ void TestCompare()
|
||||
always_check(SynthThreeWayCompare(FTestPartialOrdering( 0), FTestPartialOrdering(-1)) == partial_ordering::greater);
|
||||
|
||||
always_check(SynthThreeWayCompare(FTestPartialOrdering( 0, true), FTestPartialOrdering( 0, false)) == partial_ordering::unordered);
|
||||
|
||||
|
||||
always_check(SynthThreeWayCompare(FTestSynth(-1), FTestSynth( 0)) == weak_ordering::less);
|
||||
always_check(SynthThreeWayCompare(FTestSynth( 0), FTestSynth( 0)) == weak_ordering::equivalent);
|
||||
always_check(SynthThreeWayCompare(FTestSynth( 0), FTestSynth(-1)) == weak_ordering::greater);
|
||||
@ -285,6 +280,15 @@ void TestVarArgs()
|
||||
);
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
void TestMiscellaneous()
|
||||
{
|
||||
NAMESPACE_PRIVATE::TestAssertionMacros();
|
||||
NAMESPACE_PRIVATE::TestCompare();
|
||||
NAMESPACE_PRIVATE::TestVarArgs();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
@ -1,6 +1,6 @@
|
||||
#include "Testing/NumericTesting.h"
|
||||
#include "Testing/Testing.h"
|
||||
|
||||
#include "Numeric/Numeric.h"
|
||||
#include "Numerics/Numerics.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
@ -9,12 +9,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
void TestNumeric()
|
||||
{
|
||||
TestLiteral();
|
||||
TestBit();
|
||||
TestMath();
|
||||
}
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
void TestLiteral()
|
||||
{
|
||||
@ -606,6 +601,15 @@ void TestMath()
|
||||
always_check(static_cast<uint8>(Math::LerpStable(0, 255, 1.0)) == 255);
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
void TestNumeric()
|
||||
{
|
||||
NAMESPACE_PRIVATE::TestLiteral();
|
||||
NAMESPACE_PRIVATE::TestBit();
|
||||
NAMESPACE_PRIVATE::TestMath();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
471
Redcraft.Utility/Source/Private/Testing/Ranges.cpp
Normal file
471
Redcraft.Utility/Source/Private/Testing/Ranges.cpp
Normal file
@ -0,0 +1,471 @@
|
||||
#include "Testing/Testing.h"
|
||||
|
||||
#include "Ranges/Ranges.h"
|
||||
#include "Containers/Array.h"
|
||||
#include "Containers/List.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
void TestConversion()
|
||||
{
|
||||
{
|
||||
const TArray<int> Arr = { 1, 2, 3, 4, 5 };
|
||||
const TList<int> List = { 1, 2, 3, 4, 5 };
|
||||
|
||||
const TArray<int> Brr = Ranges::View(List.Begin(), List.End()) | Ranges::To<TArray<int>>();
|
||||
const TList<int> Mist = Ranges::View(Arr.Begin(), Arr.End()) | Ranges::To<TList<int>>();
|
||||
|
||||
always_check(Arr == Brr);
|
||||
always_check(List == Mist);
|
||||
}
|
||||
|
||||
{
|
||||
const TArray<int> Arr = { 1, 2, 3, 4, 5 };
|
||||
const TList<int> List = { 1, 2, 3, 4, 5 };
|
||||
|
||||
const TArray<int> Brr = Ranges::View(List.Begin(), List.End()) | Ranges::To<TArray>();
|
||||
const TList<int> Mist = Ranges::View(Arr.Begin(), Arr.End()) | Ranges::To<TList>();
|
||||
|
||||
always_check(Arr == Brr);
|
||||
always_check(List == Mist);
|
||||
}
|
||||
}
|
||||
|
||||
void TestFactory()
|
||||
{
|
||||
{
|
||||
const TArray<int> Arr = { };
|
||||
const TArray<int> Brr = Ranges::Empty<int> | Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Arr == Brr);
|
||||
}
|
||||
|
||||
{
|
||||
const TArray<int> Arr = { 1 };
|
||||
const TArray<int> Brr = Ranges::Single(1) | Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Arr == Brr);
|
||||
}
|
||||
|
||||
{
|
||||
const TArray<int> Arr = { 0, 1, 2, 3, 4 };
|
||||
const TArray<int> Brr = Ranges::Iota(0, 5) | Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Arr == Brr);
|
||||
}
|
||||
|
||||
{
|
||||
auto View = Ranges::Iota(0, 5);
|
||||
|
||||
always_check(View.Num() == 5);
|
||||
always_check(!View.IsEmpty());
|
||||
always_check(!!View);
|
||||
|
||||
always_check(View.Front() == 0);
|
||||
|
||||
auto First = View.Begin();
|
||||
auto Last = View.End();
|
||||
|
||||
auto ConstFirst = AsConst(View).Begin();
|
||||
auto ConstLast = AsConst(View).End();
|
||||
|
||||
always_check(First == ConstFirst);
|
||||
always_check(Last == ConstLast );
|
||||
|
||||
ConstFirst = First;
|
||||
ConstLast = Last;
|
||||
|
||||
auto Iter = ConstFirst;
|
||||
auto Jter = ConstLast;
|
||||
|
||||
++Iter;
|
||||
|
||||
always_check(*Iter++ == 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto View = Ranges::Iota(0);
|
||||
|
||||
always_check(!View.IsEmpty());
|
||||
always_check(!!View);
|
||||
|
||||
always_check(View.Front() == 0);
|
||||
|
||||
auto First = View.Begin();
|
||||
auto Last = View.End();
|
||||
|
||||
auto ConstFirst = AsConst(View).Begin();
|
||||
auto ConstLast = AsConst(View).End();
|
||||
|
||||
always_check(First == ConstFirst);
|
||||
|
||||
ConstFirst = First;
|
||||
ConstLast = Last;
|
||||
|
||||
auto Iter = ConstFirst;
|
||||
auto Jter = ConstLast;
|
||||
|
||||
++Iter;
|
||||
|
||||
always_check(*Iter++ == 1);
|
||||
}
|
||||
|
||||
{
|
||||
const TArray<int> Arr = { 0, 0, 0, 0, 0 };
|
||||
const TArray<int> Brr = Ranges::Repeat(0, 5) | Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Arr == Brr);
|
||||
}
|
||||
|
||||
{
|
||||
auto View = Ranges::Repeat(0, 8);
|
||||
|
||||
always_check(View.Num() == 8);
|
||||
always_check(!View.IsEmpty());
|
||||
always_check(!!View);
|
||||
|
||||
always_check(View.Front() == 0);
|
||||
always_check(View.Back() == 0);
|
||||
|
||||
auto First = View.Begin();
|
||||
auto Last = View.End();
|
||||
|
||||
auto ConstFirst = AsConst(View).Begin();
|
||||
auto ConstLast = AsConst(View).End();
|
||||
|
||||
always_check(First == ConstFirst);
|
||||
always_check(Last == ConstLast );
|
||||
|
||||
always_check(ConstLast - First == 8);
|
||||
|
||||
ConstFirst = First;
|
||||
ConstLast = Last;
|
||||
|
||||
auto Iter = ConstFirst;
|
||||
auto Jter = ConstLast;
|
||||
|
||||
++Iter;
|
||||
--Jter;
|
||||
|
||||
always_check(*Iter++ == 0);
|
||||
always_check(*Jter-- == 0);
|
||||
|
||||
Iter += 2;
|
||||
Jter -= 2;
|
||||
|
||||
always_check(Iter[-1] == 0);
|
||||
always_check(Jter[ 1] == 0);
|
||||
|
||||
Iter = Iter - 2;
|
||||
Jter = Jter + 2;
|
||||
|
||||
always_check(*Iter == 0);
|
||||
always_check(*Jter == 0);
|
||||
|
||||
Iter = 2 + Iter;
|
||||
Jter = Jter - 2;
|
||||
|
||||
always_check(Iter - Jter == 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto View = Ranges::Repeat(0);
|
||||
|
||||
always_check(!View.IsEmpty());
|
||||
always_check(!!View);
|
||||
|
||||
always_check(View.Front() == 0);
|
||||
|
||||
auto First = View.Begin();
|
||||
auto Last = View.End();
|
||||
|
||||
auto ConstFirst = AsConst(View).Begin();
|
||||
auto ConstLast = AsConst(View).End();
|
||||
|
||||
always_check(First == ConstFirst);
|
||||
|
||||
ConstFirst = First;
|
||||
ConstLast = Last;
|
||||
|
||||
auto Iter = ConstFirst;
|
||||
auto Jter = ConstFirst + 8;
|
||||
|
||||
++Iter;
|
||||
--Jter;
|
||||
|
||||
always_check(*Iter++ == 0);
|
||||
always_check(*Jter-- == 0);
|
||||
|
||||
Iter += 2;
|
||||
Jter -= 2;
|
||||
|
||||
always_check(Iter[-1] == 0);
|
||||
always_check(Jter[ 1] == 0);
|
||||
|
||||
Iter = Iter - 2;
|
||||
Jter = Jter + 2;
|
||||
|
||||
always_check(*Iter == 0);
|
||||
always_check(*Jter == 0);
|
||||
|
||||
Iter = 2 + Iter;
|
||||
Jter = Jter - 2;
|
||||
|
||||
always_check(Iter - Jter == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void TestAllView()
|
||||
{
|
||||
TArray<int> Arr = { 0, 1, 2, 3, 4 };
|
||||
|
||||
TArray<int> Brr = Ranges::All(Arr) | Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Arr == Brr);
|
||||
|
||||
auto View = Ranges::All(MoveTemp(Arr));
|
||||
|
||||
Arr.Reset();
|
||||
|
||||
TArray<int> Crr = View | Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Brr == Crr);
|
||||
}
|
||||
|
||||
void TestMoveView()
|
||||
{
|
||||
{
|
||||
struct FTracker
|
||||
{
|
||||
FTracker() = default;
|
||||
FTracker(const FTracker&) { always_check_no_entry(); }
|
||||
FTracker(FTracker&&) = default;
|
||||
~FTracker() = default;
|
||||
FTracker& operator=(const FTracker&) { always_check_no_entry(); }
|
||||
FTracker& operator=(FTracker&&) = default;
|
||||
};
|
||||
|
||||
FTracker Arr[2];
|
||||
|
||||
auto View = Arr | Ranges::Move();
|
||||
|
||||
auto First = View.Begin();
|
||||
auto Last = View.End();
|
||||
|
||||
FTracker Temp(*First++);
|
||||
|
||||
Temp = *First++;
|
||||
|
||||
always_check(First == Last);
|
||||
}
|
||||
|
||||
{
|
||||
TArray<int> Arr = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
auto View = Arr | Ranges::Move();
|
||||
|
||||
always_check(View.Num() == 8);
|
||||
always_check(!View.IsEmpty());
|
||||
always_check(!!View);
|
||||
|
||||
always_check(View.Front() == 0);
|
||||
always_check(View.Back() == 7);
|
||||
|
||||
auto First = View.Begin();
|
||||
auto Last = View.End();
|
||||
|
||||
auto ConstFirst = AsConst(View).Begin();
|
||||
auto ConstLast = AsConst(View).End();
|
||||
|
||||
always_check(First == ConstFirst);
|
||||
always_check(Last == ConstLast );
|
||||
|
||||
always_check(ConstLast - First == 8);
|
||||
|
||||
ConstFirst = First;
|
||||
ConstLast = Last;
|
||||
|
||||
auto Iter = ConstFirst;
|
||||
auto Jter = ConstLast;
|
||||
|
||||
++Iter;
|
||||
--Jter;
|
||||
|
||||
always_check(*Iter++ == 1);
|
||||
always_check(*Jter-- == 7);
|
||||
|
||||
Iter += 2;
|
||||
Jter -= 2;
|
||||
|
||||
always_check(Iter[-1] == 3);
|
||||
always_check(Jter[ 1] == 5);
|
||||
|
||||
Iter = Iter - 2;
|
||||
Jter = Jter + 2;
|
||||
|
||||
always_check(*Iter == 2);
|
||||
always_check(*Jter == 6);
|
||||
|
||||
Iter = 2 + Iter;
|
||||
Jter = Jter - 2;
|
||||
|
||||
always_check(Iter - Jter == 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto View = Ranges::Iota(0) | Ranges::Move();
|
||||
|
||||
always_check(!View.IsEmpty());
|
||||
always_check(!!View);
|
||||
|
||||
always_check(View.Front() == 0);
|
||||
|
||||
auto First = View.Begin();
|
||||
auto Last = View.End();
|
||||
|
||||
auto ConstFirst = AsConst(View).Begin();
|
||||
auto ConstLast = AsConst(View).End();
|
||||
|
||||
always_check(First == ConstFirst);
|
||||
|
||||
ConstFirst = First;
|
||||
ConstLast = Last;
|
||||
|
||||
auto Iter = ConstFirst;
|
||||
auto Jter = ConstLast;
|
||||
|
||||
++Iter;
|
||||
|
||||
always_check(*Iter++ == 1);
|
||||
}
|
||||
}
|
||||
|
||||
void TestMiscView()
|
||||
{
|
||||
{
|
||||
TArray<int> Arr = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
TArray<int> Brr = { 0, 2, 4, 6 };
|
||||
|
||||
TArray<int> Crr = Arr
|
||||
| Ranges::Filter([](int Value) { return Value % 2 == 0; })
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Brr == Crr);
|
||||
}
|
||||
|
||||
{
|
||||
TArray<int> Arr = { 0, 1, 2, 2, 1, 0 };
|
||||
TArray<int> Brr = { 0, 2, 4, 4, 2, 0 };
|
||||
|
||||
TArray<int> Crr = Arr
|
||||
| Ranges::Transform([](int Value) { return Value * 2; })
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Brr == Crr);
|
||||
}
|
||||
|
||||
{
|
||||
TArray<int> Arr = { 0, 1, 2, 3, 3, 2, 1, 0 };
|
||||
TArray<int> Brr = { 0, 2, 4, 4, 2, 0 };
|
||||
|
||||
TArray<int> Crr = Arr
|
||||
| Ranges::Filter ([](int Value) { return Value < 3; })
|
||||
| Ranges::Transform([](int Value) { return Value * 2; })
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
TArray<int> Drr = Arr
|
||||
| Ranges::Transform([](int Value) { return Value * 2; })
|
||||
| Ranges::Filter ([](int Value) { return Value < 6; })
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Brr == Crr);
|
||||
always_check(Brr == Drr);
|
||||
}
|
||||
|
||||
{
|
||||
TArray<int> Arr = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
TArray<int> Brr = Ranges::Iota(0)
|
||||
| Ranges::Take(8)
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
TArray<int> Crr = Ranges::Iota(0)
|
||||
| Ranges::TakeWhile([](int Value) { return Value < 8; })
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Arr == Brr);
|
||||
always_check(Arr == Crr);
|
||||
}
|
||||
|
||||
{
|
||||
TArray<int> Arr = { 0, 4, 7, 8, 3, 1, 10 };
|
||||
TArray<int> Brr = { 0, 2, 4 };
|
||||
|
||||
TArray<int> Crr = Arr
|
||||
| Ranges::Filter ([](int Value) { return Value % 2 == 0; })
|
||||
| Ranges::Take(3)
|
||||
| Ranges::Transform([](int Value) { return Value / 2; })
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
TArray<int> Drr = Arr
|
||||
| Ranges::Filter ([](int Value) { return Value % 2 == 0; })
|
||||
| Ranges::TakeWhile([](int Value) { return Value < 10; })
|
||||
| Ranges::Transform([](int Value) { return Value / 2; })
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
TArray<int> Err = Arr
|
||||
| Ranges::Filter ([](int Value) { return Value % 2 == 0; })
|
||||
| Ranges::Transform([](int Value) { return Value / 2; })
|
||||
| Ranges::Take(3)
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
TArray<int> Frr = Arr
|
||||
| Ranges::Filter ([](int Value) { return Value % 2 == 0; })
|
||||
| Ranges::Transform([](int Value) { return Value / 2; })
|
||||
| Ranges::TakeWhile([](int Value) { return Value < 5; })
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
TArray<int> Grr = Arr
|
||||
| Ranges::Take(6)
|
||||
| Ranges::Filter ([](int Value) { return Value % 2 == 0; })
|
||||
| Ranges::Transform([](int Value) { return Value / 2; })
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
TArray<int> Hrr = Arr
|
||||
| Ranges::TakeWhile([](int Value) { return Value < 10; })
|
||||
| Ranges::Filter ([](int Value) { return Value % 2 == 0; })
|
||||
| Ranges::Transform([](int Value) { return Value / 2; })
|
||||
| Ranges::To<TArray<int>>();
|
||||
|
||||
always_check(Brr == Crr);
|
||||
always_check(Brr == Drr);
|
||||
always_check(Brr == Err);
|
||||
always_check(Brr == Frr);
|
||||
always_check(Brr == Grr);
|
||||
always_check(Brr == Hrr);
|
||||
}
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
void TestRange()
|
||||
{
|
||||
NAMESPACE_PRIVATE::TestConversion();
|
||||
NAMESPACE_PRIVATE::TestFactory();
|
||||
NAMESPACE_PRIVATE::TestAllView();
|
||||
NAMESPACE_PRIVATE::TestMoveView();
|
||||
NAMESPACE_PRIVATE::TestMiscView();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,10 +1,11 @@
|
||||
#include "Testing/StringTesting.h"
|
||||
#include "Testing/Testing.h"
|
||||
|
||||
#include "String/Char.h"
|
||||
#include "Strings/Char.h"
|
||||
#include "Memory/Memory.h"
|
||||
#include "String/String.h"
|
||||
#include "Numeric/Numeric.h"
|
||||
#include "String/StringView.h"
|
||||
#include "Numerics/Numerics.h"
|
||||
#include "Strings/String.h"
|
||||
#include "Strings/StringView.h"
|
||||
#include "Strings/Convert.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
@ -13,13 +14,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
void TestString()
|
||||
{
|
||||
TestChar();
|
||||
TestStringView();
|
||||
TestTemplateString();
|
||||
TestStringConversion();
|
||||
}
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
void TestChar()
|
||||
{
|
||||
@ -32,6 +27,7 @@ void TestChar()
|
||||
always_check(CCharType<u32char>);
|
||||
always_check(CCharType<unicodechar>);
|
||||
}
|
||||
|
||||
auto Test = []<typename T>(TInPlaceType<T>)
|
||||
{
|
||||
always_check(TChar<T>::IsASCII(LITERAL(T, '0')));
|
||||
@ -201,10 +197,11 @@ void TestStringView()
|
||||
{
|
||||
always_check( LITERAL_VIEW(T, "012345678900").IsASCII());
|
||||
always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").IsASCII());
|
||||
always_check( LITERAL_VIEW(T, "012345678900").IsInteger());
|
||||
always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").IsInteger());
|
||||
always_check(!LITERAL_VIEW(T, "0123456789AB").IsInteger());
|
||||
always_check( LITERAL_VIEW(T, "0123456789AB").IsInteger(16));
|
||||
|
||||
always_check( LITERAL_VIEW(T, "012345678900").template IsInteger<uint64>(10));
|
||||
always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").template IsInteger<uint64>(10));
|
||||
always_check(!LITERAL_VIEW(T, "0123456789AB").template IsInteger<uint64>(10));
|
||||
always_check( LITERAL_VIEW(T, "0123456789AB").template IsInteger<uint64>(16));
|
||||
}
|
||||
};
|
||||
|
||||
@ -216,7 +213,7 @@ void TestStringView()
|
||||
Test(InPlaceType<unicodechar>);
|
||||
}
|
||||
|
||||
void TestTemplateString()
|
||||
void TestString()
|
||||
{
|
||||
auto Test = []<typename T>(TInPlaceType<T>)
|
||||
{
|
||||
@ -453,38 +450,17 @@ void TestTemplateString()
|
||||
Test(InPlaceType<unicodechar>);
|
||||
}
|
||||
|
||||
void TestStringConversion()
|
||||
void TestConvert()
|
||||
{
|
||||
auto Test = []<typename T>(TInPlaceType<T>)
|
||||
{
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), true ) == LITERAL(T, "#True#" ));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), false) == LITERAL(T, "#False#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), +0) == LITERAL(T, "#0#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), 0) == LITERAL(T, "#0#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), -0) == LITERAL(T, "#0#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), 42) == LITERAL(T, "#42#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), +0.0) == LITERAL(T, "#0.000000#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), 0.0) == LITERAL(T, "#0.000000#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), -0.0) == LITERAL(T, "#-0.000000#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), 3.14) == LITERAL(T, "#3.140000#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), +TNumericLimits<float>::Infinity()) == LITERAL(T, "#Infinity#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), -TNumericLimits<float>::Infinity()) == LITERAL(T, "#-Infinity#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), +TNumericLimits<float>::QuietNaN()) == LITERAL(T, "#NaN#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{}#"), -TNumericLimits<float>::QuietNaN()) == LITERAL(T, "#-NaN#"));
|
||||
|
||||
auto CheckParseArithmetic = []<typename U>(TStringView<T> View, U Result)
|
||||
{
|
||||
U Object;
|
||||
|
||||
if constexpr (CSameAs<U, bool>) always_check(View.Parse(LITERAL(T, "{0:}"), Object) == 1);
|
||||
else if constexpr (CIntegral<U>) always_check(View.Parse(LITERAL(T, "{0:+#I}"), Object) == 1);
|
||||
else if constexpr (CFloatingPoint<U>) always_check(View.Parse(LITERAL(T, "{0:+#G}"), Object) == 1);
|
||||
if constexpr (CSameAs<U, bool>) always_check(View.Parse(Object));
|
||||
else if constexpr (CIntegral<U>) always_check(View.Parse(Object));
|
||||
else if constexpr (CFloatingPoint<U>) always_check(View.Parse(Object));
|
||||
|
||||
if constexpr (CFloatingPoint<U>)
|
||||
{
|
||||
@ -559,6 +535,68 @@ void TestStringConversion()
|
||||
CheckParseFloat(InPlaceType<float>);
|
||||
CheckParseFloat(InPlaceType<double>);
|
||||
|
||||
{
|
||||
always_check( LITERAL_VIEW(T, "true" ).ToBool());
|
||||
always_check(!LITERAL_VIEW(T, "false").ToBool());
|
||||
always_check( LITERAL_VIEW(T, "True" ).ToBool());
|
||||
always_check(!LITERAL_VIEW(T, "False").ToBool());
|
||||
}
|
||||
|
||||
{
|
||||
always_check(LITERAL_VIEW(T, "42" ).ToInt() == 42 );
|
||||
always_check(LITERAL_VIEW(T, "FF" ).ToInt(16) == 255);
|
||||
always_check(LITERAL_VIEW(T, "-42").ToInt() == -42);
|
||||
always_check(LITERAL_VIEW(T, "0" ).ToInt() == 0 );
|
||||
}
|
||||
|
||||
{
|
||||
always_check(LITERAL_VIEW(T, "3.14" ).ToFloat() == 3.14f);
|
||||
always_check(LITERAL_VIEW(T, "3.14e+00").ToFloat() == 3.14f);
|
||||
always_check(LITERAL_VIEW(T, "-3.14" ).ToFloat() == -3.14f);
|
||||
always_check(LITERAL_VIEW(T, "0.0" ).ToFloat() == 0.0f);
|
||||
}
|
||||
};
|
||||
|
||||
Test(InPlaceType<char>);
|
||||
Test(InPlaceType<wchar>);
|
||||
Test(InPlaceType<u8char>);
|
||||
Test(InPlaceType<u16char>);
|
||||
Test(InPlaceType<u32char>);
|
||||
Test(InPlaceType<unicodechar>);
|
||||
}
|
||||
|
||||
void TestFormatting()
|
||||
{
|
||||
auto Test = []<typename T>(TInPlaceType<T>)
|
||||
{
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), LITERAL(T, "Hello, World!")) == LITERAL(T, "#Hello, World!#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), true ) == LITERAL(T, "#True#" ));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), false) == LITERAL(T, "#False#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), +0) == LITERAL(T, "#0#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), 0) == LITERAL(T, "#0#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), -0) == LITERAL(T, "#0#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), 42) == LITERAL(T, "#42#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), +0.0) == LITERAL(T, "#0#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), 0.0) == LITERAL(T, "#0#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), -0.0) == LITERAL(T, "#-0#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), 3.14) == LITERAL(T, "#3.14#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0:.6F}#"), +0.0) == LITERAL(T, "#0.000000#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0:.6F}#"), 0.0) == LITERAL(T, "#0.000000#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0:.6F}#"), -0.0) == LITERAL(T, "#-0.000000#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0:.6F}#"), 3.14) == LITERAL(T, "#3.140000#"));
|
||||
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), +TNumericLimits<float>::Infinity()) == LITERAL(T, "#Infinity#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), -TNumericLimits<float>::Infinity()) == LITERAL(T, "#-Infinity#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), +TNumericLimits<float>::QuietNaN()) == LITERAL(T, "#NaN#"));
|
||||
always_check(TString<T>::Format(LITERAL(T, "#{0}#"), -TNumericLimits<float>::QuietNaN()) == LITERAL(T, "#-NaN#"));
|
||||
|
||||
{
|
||||
always_check(TString<T>::FromBool(true ) == LITERAL(T, "True" ));
|
||||
always_check(TString<T>::FromBool(false) == LITERAL(T, "False"));
|
||||
@ -584,37 +622,6 @@ void TestStringConversion()
|
||||
always_check(TString<T>::FromFloat(3.14f, false, false, 2) == LITERAL(T, "1.92p+1" ));
|
||||
always_check(TString<T>::FromFloat(1.0f / 3.0f, true, false, 5) == LITERAL(T, "0.33333" ));
|
||||
}
|
||||
|
||||
{
|
||||
always_check( LITERAL_VIEW(T, "True" ).ToBool());
|
||||
always_check(!LITERAL_VIEW(T, "False" ).ToBool());
|
||||
always_check( LITERAL_VIEW(T, "1" ).ToBool());
|
||||
always_check(!LITERAL_VIEW(T, "0" ).ToBool());
|
||||
always_check(!LITERAL_VIEW(T, "random").ToBool());
|
||||
}
|
||||
|
||||
{
|
||||
always_check(LITERAL_VIEW(T, "42" ).ToInt() == 42 );
|
||||
always_check(LITERAL_VIEW(T, "FF" ).ToInt(16) == 255);
|
||||
always_check(LITERAL_VIEW(T, "-42" ).ToInt() == -42);
|
||||
always_check(LITERAL_VIEW(T, "0" ).ToInt() == 0 );
|
||||
always_check(LITERAL_VIEW(T, "Invalid").ToInt() == 0 );
|
||||
|
||||
always_check(LITERAL_VIEW(T, "999999999999999999999999999999").ToInt() == 0);
|
||||
always_check(LITERAL_VIEW(T, "-999999999999999999999999999999").ToInt() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
always_check(LITERAL_VIEW(T, "3.14" ).ToFloat() == 3.14f);
|
||||
always_check(LITERAL_VIEW(T, "3.14e+00").ToFloat() == 3.14f);
|
||||
always_check(LITERAL_VIEW(T, "-3.14" ).ToFloat() == -3.14f);
|
||||
always_check(LITERAL_VIEW(T, "0.0" ).ToFloat() == 0.0f);
|
||||
|
||||
always_check(Math::IsNaN(LITERAL_VIEW(T, "1e+308").ToFloat()));
|
||||
always_check(Math::IsNaN(LITERAL_VIEW(T, "-1e+308").ToFloat()));
|
||||
always_check(Math::IsNaN(LITERAL_VIEW(T, "1e-308").ToFloat()));
|
||||
always_check(Math::IsNaN(LITERAL_VIEW(T, "-1e-308").ToFloat()));
|
||||
}
|
||||
};
|
||||
|
||||
Test(InPlaceType<char>);
|
||||
@ -625,6 +632,17 @@ void TestStringConversion()
|
||||
Test(InPlaceType<unicodechar>);
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
void TestString()
|
||||
{
|
||||
NAMESPACE_PRIVATE::TestChar();
|
||||
NAMESPACE_PRIVATE::TestStringView();
|
||||
NAMESPACE_PRIVATE::TestString();
|
||||
NAMESPACE_PRIVATE::TestConvert();
|
||||
NAMESPACE_PRIVATE::TestFormatting();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
@ -1,4 +1,4 @@
|
||||
#include "Testing/TemplatesTesting.h"
|
||||
#include "Testing/Testing.h"
|
||||
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
@ -14,20 +14,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
void TestTemplates()
|
||||
{
|
||||
TestInvoke();
|
||||
TestReferenceWrapper();
|
||||
TestOptional();
|
||||
TestVariant();
|
||||
TestAny();
|
||||
TestTuple();
|
||||
TestFunction();
|
||||
TestAtomic();
|
||||
TestScopeHelper();
|
||||
TestPropagateConst();
|
||||
TestMiscTemplates();
|
||||
}
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
NAMESPACE_UNNAMED_BEGIN
|
||||
|
||||
@ -1014,13 +1001,13 @@ void TestTuple()
|
||||
{
|
||||
TTuple<int32, char> TempA = { 1, 'A' };
|
||||
|
||||
TempA.Visit([](auto&& A) { A++; });
|
||||
TempA.Visit([](auto&& A) -> void { ++A; });
|
||||
|
||||
TempA.Visit(
|
||||
[]<typename T> (T&& A)
|
||||
{
|
||||
if constexpr (CSameAs<T&&, int32&>) always_check(A == 2);
|
||||
else if constexpr (CSameAs<T&&, char&>) always_check(A == 'B');
|
||||
if constexpr (CSameAs<T&&, int32&>) always_check(A == 2 );
|
||||
else if constexpr (CSameAs<T&&, char &>) always_check(A == 'B');
|
||||
else always_check_no_entry();
|
||||
}
|
||||
);
|
||||
@ -1621,6 +1608,23 @@ void TestMiscTemplates()
|
||||
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
void TestTemplates()
|
||||
{
|
||||
NAMESPACE_PRIVATE::TestInvoke();
|
||||
NAMESPACE_PRIVATE::TestReferenceWrapper();
|
||||
NAMESPACE_PRIVATE::TestOptional();
|
||||
NAMESPACE_PRIVATE::TestVariant();
|
||||
NAMESPACE_PRIVATE::TestAny();
|
||||
NAMESPACE_PRIVATE::TestTuple();
|
||||
NAMESPACE_PRIVATE::TestFunction();
|
||||
NAMESPACE_PRIVATE::TestAtomic();
|
||||
NAMESPACE_PRIVATE::TestScopeHelper();
|
||||
NAMESPACE_PRIVATE::TestPropagateConst();
|
||||
NAMESPACE_PRIVATE::TestMiscTemplates();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
@ -1,4 +1,4 @@
|
||||
#include "Testing/TypeTraitsTesting.h"
|
||||
#include "Testing/Testing.h"
|
||||
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
5
Redcraft.Utility/Source/Public/Algorithms/Algorithms.h
Normal file
5
Redcraft.Utility/Source/Public/Algorithms/Algorithms.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Algorithms/Basic.h"
|
||||
#include "Algorithms/Search.h"
|
188
Redcraft.Utility/Source/Public/Algorithms/Basic.h
Normal file
188
Redcraft.Utility/Source/Public/Algorithms/Basic.h
Normal file
@ -0,0 +1,188 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Numerics/Math.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Algorithms)
|
||||
|
||||
/** Increments given iterator 'Iter' by 'N' elements. */
|
||||
template <CInputOrOutputIterator I>
|
||||
FORCEINLINE constexpr void Advance(I& Iter, ptrdiff N)
|
||||
{
|
||||
if constexpr (CRandomAccessIterator<I>)
|
||||
{
|
||||
Iter += N;
|
||||
}
|
||||
|
||||
else if constexpr (CBidirectionalIterator<I>)
|
||||
{
|
||||
for (; N > 0; --N) ++Iter;
|
||||
for (; N < 0; ++N) --Iter;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
checkf(N >= 0, TEXT("The iterator must satisfy the CBidirectionalIterator in order to be decremented."));
|
||||
|
||||
for (; N > 0; --N) ++Iter;
|
||||
}
|
||||
}
|
||||
|
||||
/** Increments given iterator 'Iter' to the 'Sent' position. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||
FORCEINLINE constexpr void Advance(I& Iter, S Sent)
|
||||
{
|
||||
if constexpr (CAssignableFrom<I&, S>)
|
||||
{
|
||||
Iter = Sent;
|
||||
}
|
||||
|
||||
else if constexpr (CSizedSentinelFor<S, I>)
|
||||
{
|
||||
Algorithms::Advance(Iter, Sent - Iter);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
for (; Iter != Sent; ++Iter);
|
||||
}
|
||||
}
|
||||
|
||||
/** Increments given iterator 'Iter' by 'N' elements, up to the 'Sent' position. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||
FORCEINLINE constexpr ptrdiff Advance(I& Iter, ptrdiff N, S Sent)
|
||||
{
|
||||
if constexpr (CSizedSentinelFor<S, I>)
|
||||
{
|
||||
const ptrdiff Distance = Sent - Iter;
|
||||
|
||||
if (Math::Abs(N) > Math::Abs(Distance))
|
||||
{
|
||||
Algorithms::Advance(Iter, Sent);
|
||||
|
||||
return N - Distance;
|
||||
}
|
||||
|
||||
Algorithms::Advance(Iter, N);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
else if constexpr (CBidirectionalIterator<I>)
|
||||
{
|
||||
for (; N > 0 && Iter != Sent; --N) ++Iter;
|
||||
for (; N < 0 && Iter != Sent; ++N) --Iter;
|
||||
|
||||
return N;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
checkf(N >= 0, TEXT("The iterator must satisfy the CBidirectionalIterator in order to be decremented."));
|
||||
|
||||
for (; N > 0 && Iter != Sent; --N) ++Iter;
|
||||
|
||||
return N;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return The number of hops from 'First' to 'Last'. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||
NODISCARD FORCEINLINE constexpr ptrdiff Distance(I First, S Last)
|
||||
{
|
||||
if constexpr (CSizedSentinelFor<S, I>)
|
||||
{
|
||||
return Last - First;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
ptrdiff Result = 0;
|
||||
|
||||
for (; First != Last; ++First) ++Result;
|
||||
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return The size of the range. The range will not be modified if it is a sized range. */
|
||||
template <CRange R>
|
||||
NODISCARD FORCEINLINE constexpr ptrdiff Distance(R&& Range)
|
||||
{
|
||||
if constexpr (CSizedRange<R&>)
|
||||
{
|
||||
return static_cast<ptrdiff>(Ranges::Num(Range));
|
||||
}
|
||||
|
||||
else return Algorithms::Distance(Ranges::Begin(Range), Ranges::End(Range));
|
||||
}
|
||||
|
||||
/** @return The 1-th successor of iterator 'Iter'. */
|
||||
template <CInputOrOutputIterator I>
|
||||
NODISCARD FORCEINLINE constexpr I Next(I Iter)
|
||||
{
|
||||
return ++Iter;
|
||||
}
|
||||
|
||||
/** @return The 'N'-th successor of iterator 'Iter'. */
|
||||
template <CInputOrOutputIterator I>
|
||||
NODISCARD FORCEINLINE constexpr I Next(I Iter, ptrdiff N)
|
||||
{
|
||||
Algorithms::Advance(Iter, N);
|
||||
return Iter;
|
||||
}
|
||||
|
||||
/** @return The successor of iterator 'Iter' to the 'Sent' position. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||
NODISCARD FORCEINLINE constexpr I Next(I Iter, S Sent)
|
||||
{
|
||||
Algorithms::Advance(Iter, Sent);
|
||||
return Iter;
|
||||
}
|
||||
|
||||
/** @return The 'N'-th successor of iterator 'Iter', up to the 'Sent' position. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||
NODISCARD FORCEINLINE constexpr I Next(I Iter, ptrdiff N, S Sent)
|
||||
{
|
||||
Algorithms::Advance(Iter, N, Sent);
|
||||
return Iter;
|
||||
}
|
||||
|
||||
/** @return The 1-th predecessor of iterator 'Iter'. */
|
||||
template <CBidirectionalIterator I>
|
||||
NODISCARD FORCEINLINE constexpr I Prev(I Iter)
|
||||
{
|
||||
return --Iter;
|
||||
}
|
||||
|
||||
/** @return The 'N'-th predecessor of iterator 'Iter'. */
|
||||
template <CBidirectionalIterator I>
|
||||
NODISCARD FORCEINLINE constexpr I Prev(I Iter, ptrdiff N)
|
||||
{
|
||||
Algorithms::Advance(Iter, -N);
|
||||
return Iter;
|
||||
}
|
||||
|
||||
/** @return The predecessor of iterator 'Iter', up to the 'First' position. */
|
||||
template <CBidirectionalIterator I>
|
||||
NODISCARD FORCEINLINE constexpr I Prev(I Iter, ptrdiff N, I First)
|
||||
{
|
||||
Algorithms::Advance(Iter, -N, First);
|
||||
return Iter;
|
||||
}
|
||||
|
||||
NAMESPACE_END(Algorithms)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
1755
Redcraft.Utility/Source/Public/Algorithms/Search.h
Normal file
1755
Redcraft.Utility/Source/Public/Algorithms/Search.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -4,14 +4,14 @@
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/TypeHash.h"
|
||||
#include "Memory/Allocator.h"
|
||||
#include "Memory/Allocators.h"
|
||||
#include "Memory/MemoryOperator.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/ReverseIterator.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Range/Factory.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Factory.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
@ -60,7 +60,7 @@ public:
|
||||
|
||||
/** Constructs the container with 'Count' copies of elements with 'InValue'. */
|
||||
FORCEINLINE explicit TArray(size_t Count, const FElementType& InValue) requires (CCopyConstructible<T>)
|
||||
: TArray(Range::Repeat(InValue, Count))
|
||||
: TArray(Ranges::Repeat(InValue, Count))
|
||||
{ }
|
||||
|
||||
/** Constructs the container with the contents of the range ['First', 'Last'). */
|
||||
@ -104,7 +104,7 @@ public:
|
||||
|
||||
/** Constructs the container with the contents of the range. */
|
||||
template <CInputRange R> requires (!CSameAs<TRemoveCVRef<R>, TArray> && CConstructibleFrom<T, TRangeReference<R>> && CMovable<T>)
|
||||
FORCEINLINE explicit TArray(R&& Range) : TArray(Range::Begin(Range), Range::End(Range)) { }
|
||||
FORCEINLINE explicit TArray(R&& Range) : TArray(Ranges::Begin(Range), Ranges::End(Range)) { }
|
||||
|
||||
/** Copy constructor. Constructs the container with the copy of the contents of 'InValue'. */
|
||||
TArray(const TArray& InValue) requires (CCopyConstructible<T>)
|
||||
@ -142,7 +142,7 @@ public:
|
||||
}
|
||||
|
||||
/** Constructs the container with the contents of the initializer list. */
|
||||
FORCEINLINE TArray(initializer_list<FElementType> IL) requires (CCopyConstructible<T>) : TArray(Range::Begin(IL), Range::End(IL)) { }
|
||||
FORCEINLINE TArray(initializer_list<FElementType> IL) requires (CCopyConstructible<T>) : TArray(Ranges::Begin(IL), Ranges::End(IL)) { }
|
||||
|
||||
/** Destructs the array. The destructors of the elements are called and the used storage is deallocated. */
|
||||
~TArray()
|
||||
@ -256,38 +256,38 @@ public:
|
||||
/** Replaces the contents with those identified by initializer list. */
|
||||
TArray& operator=(initializer_list<FElementType> IL) requires (CCopyable<T>)
|
||||
{
|
||||
size_t NumToAllocate = Range::Num(IL);
|
||||
size_t NumToAllocate = Ranges::Num(IL);
|
||||
|
||||
NumToAllocate = NumToAllocate > Max() ? Impl->CalculateSlackGrow (Range::Num(IL), Max()) : NumToAllocate;
|
||||
NumToAllocate = NumToAllocate < Max() ? Impl->CalculateSlackShrink(Range::Num(IL), Max()) : NumToAllocate;
|
||||
NumToAllocate = NumToAllocate > Max() ? Impl->CalculateSlackGrow (Ranges::Num(IL), Max()) : NumToAllocate;
|
||||
NumToAllocate = NumToAllocate < Max() ? Impl->CalculateSlackShrink(Ranges::Num(IL), Max()) : NumToAllocate;
|
||||
|
||||
if (NumToAllocate != Max())
|
||||
{
|
||||
Memory::Destruct(Impl.Pointer, Num());
|
||||
Impl->Deallocate(Impl.Pointer);
|
||||
|
||||
Impl.ArrayNum = Range::Num(IL);
|
||||
Impl.ArrayNum = Ranges::Num(IL);
|
||||
Impl.ArrayMax = NumToAllocate;
|
||||
Impl.Pointer = Impl->Allocate(Max());
|
||||
|
||||
Memory::CopyConstruct<FElementType>(Impl.Pointer, Range::GetData(IL), Num());
|
||||
Memory::CopyConstruct<FElementType>(Impl.Pointer, Ranges::GetData(IL), Num());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (Range::Num(IL) <= Num())
|
||||
if (Ranges::Num(IL) <= Num())
|
||||
{
|
||||
Memory::CopyAssign(Impl.Pointer, Range::GetData(IL), Range::Num(IL));
|
||||
Memory::Destruct(Impl.Pointer + Range::Num(IL), Num() - Range::Num(IL));
|
||||
Memory::CopyAssign(Impl.Pointer, Ranges::GetData(IL), Ranges::Num(IL));
|
||||
Memory::Destruct(Impl.Pointer + Ranges::Num(IL), Num() - Ranges::Num(IL));
|
||||
}
|
||||
else if (Range::Num(IL) <= Max())
|
||||
else if (Ranges::Num(IL) <= Max())
|
||||
{
|
||||
Memory::CopyAssign(Impl.Pointer, Range::GetData(IL), Num());
|
||||
Memory::CopyConstruct<FElementType>(Impl.Pointer + Num(), Range::GetData(IL) + Num(), Range::Num(IL) - Num());
|
||||
Memory::CopyAssign(Impl.Pointer, Ranges::GetData(IL), Num());
|
||||
Memory::CopyConstruct<FElementType>(Impl.Pointer + Num(), Ranges::GetData(IL) + Num(), Ranges::Num(IL) - Num());
|
||||
}
|
||||
else check_no_entry();
|
||||
|
||||
Impl.ArrayNum = Range::Num(IL);
|
||||
Impl.ArrayNum = Ranges::Num(IL);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -419,7 +419,7 @@ public:
|
||||
{
|
||||
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator()."));
|
||||
|
||||
return Insert(Iter, Range::Repeat(InValue, Count));
|
||||
return Insert(Iter, Ranges::Repeat(InValue, Count));
|
||||
}
|
||||
|
||||
/** Inserts elements from range ['First', 'Last') before 'Iter'. */
|
||||
@ -546,13 +546,13 @@ public:
|
||||
template <CInputRange R> requires (CConstructibleFrom<T, TRangeReference<R>> && CAssignableFrom<T&, TRangeReference<R>> && CMovable<T>)
|
||||
FORCEINLINE FIterator Insert(FConstIterator Iter, R&& Range)
|
||||
{
|
||||
return Insert(Iter, Range::Begin(Range), Range::End(Range));
|
||||
return Insert(Iter, Ranges::Begin(Range), Ranges::End(Range));
|
||||
}
|
||||
|
||||
/** Inserts elements from initializer list before 'Iter' in the container. */
|
||||
FORCEINLINE FIterator Insert(FConstIterator Iter, initializer_list<FElementType> IL) requires (CCopyable<T>)
|
||||
{
|
||||
return Insert(Iter, Range::Begin(IL), Range::End(IL));
|
||||
return Insert(Iter, Ranges::Begin(IL), Ranges::End(IL));
|
||||
}
|
||||
|
||||
/** Inserts a new element into the container directly before 'Iter'. */
|
||||
|
@ -4,10 +4,10 @@
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/TypeHash.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/ReverseIterator.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
#include "Containers/Array.h"
|
||||
#include "Containers/StaticArray.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
|
@ -5,12 +5,12 @@
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/TypeHash.h"
|
||||
#include "Templates/Noncopyable.h"
|
||||
#include "Memory/Allocator.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/ReverseIterator.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Memory/Allocators.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
@ -135,7 +135,7 @@ public:
|
||||
|
||||
/** Constructs the bitset with the bits of the range. */
|
||||
template <CInputRange R> requires (!CSameAs<TRemoveCVRef<R>, TBitset> && CConstructibleFrom<bool, TRangeReference<R>>)
|
||||
FORCEINLINE explicit TBitset(R&& Range) : TBitset(Range::Begin(Range), Range::End(Range)) { }
|
||||
FORCEINLINE explicit TBitset(R&& Range) : TBitset(Ranges::Begin(Range), Ranges::End(Range)) { }
|
||||
|
||||
/** Copy constructor. Constructs the bitset with the copy of the bits of 'InValue'. */
|
||||
FORCEINLINE TBitset(const TBitset& InValue)
|
||||
@ -171,7 +171,7 @@ public:
|
||||
}
|
||||
|
||||
/** Constructs the bitset with the bits of the initializer list. */
|
||||
FORCEINLINE TBitset(initializer_list<bool> IL) : TBitset(Range::Begin(IL), Range::End(IL)) { }
|
||||
FORCEINLINE TBitset(initializer_list<bool> IL) : TBitset(Ranges::Begin(IL), Ranges::End(IL)) { }
|
||||
|
||||
/** Destructs the bitset. The storage is deallocated. */
|
||||
~TBitset()
|
||||
@ -239,9 +239,9 @@ public:
|
||||
/** Replaces the bits with those identified by initializer list. */
|
||||
TBitset& operator=(initializer_list<bool> IL)
|
||||
{
|
||||
auto First = Range::Begin(IL);
|
||||
auto First = Ranges::Begin(IL);
|
||||
|
||||
const size_t BlocksCount = (Range::Num(IL) + BlockWidth - 1) / BlockWidth;
|
||||
const size_t BlocksCount = (Ranges::Num(IL) + BlockWidth - 1) / BlockWidth;
|
||||
|
||||
size_t NumToAllocate = BlocksCount;
|
||||
|
||||
@ -252,7 +252,7 @@ public:
|
||||
{
|
||||
Impl->Deallocate(Impl.Pointer);
|
||||
|
||||
Impl.BitsetNum = Range::Num(IL);
|
||||
Impl.BitsetNum = Ranges::Num(IL);
|
||||
Impl.BlocksMax = NumToAllocate;
|
||||
Impl.Pointer = Impl->Allocate(MaxBlocks());
|
||||
|
||||
@ -261,7 +261,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
Impl.BitsetNum = Range::Num(IL);
|
||||
Impl.BitsetNum = Ranges::Num(IL);
|
||||
|
||||
for (FReference Ref : *this) Ref = *First++;
|
||||
|
||||
|
@ -4,14 +4,14 @@
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/TypeHash.h"
|
||||
#include "Memory/Allocator.h"
|
||||
#include "Memory/Allocators.h"
|
||||
#include "Memory/MemoryOperator.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/ReverseIterator.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Range/Factory.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Factory.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
@ -79,7 +79,7 @@ public:
|
||||
|
||||
/** Constructs the container with 'Count' copies of elements with 'InValue'. */
|
||||
TList(size_t Count, const FElementType& InValue) requires (CCopyable<FElementType>)
|
||||
: TList(Range::Repeat(InValue, Count))
|
||||
: TList(Ranges::Repeat(InValue, Count))
|
||||
{ }
|
||||
|
||||
/** Constructs the container with the contents of the range ['First', 'Last'). */
|
||||
@ -106,7 +106,7 @@ public:
|
||||
|
||||
/** Constructs the container with the contents of the range. */
|
||||
template <CInputRange R> requires (!CSameAs<TRemoveCVRef<R>, TList> && CConstructibleFrom<FElementType, TRangeReference<R>>)
|
||||
FORCEINLINE explicit TList(R&& Range) : TList(Range::Begin(Range), Range::End(Range)) { }
|
||||
FORCEINLINE explicit TList(R&& Range) : TList(Ranges::Begin(Range), Ranges::End(Range)) { }
|
||||
|
||||
/** Copy constructor. Constructs the container with the copy of the contents of 'InValue'. */
|
||||
FORCEINLINE TList(const TList& InValue) requires (CCopyConstructible<FElementType>) : TList(InValue.Begin(), InValue.End()) { }
|
||||
@ -115,7 +115,7 @@ public:
|
||||
FORCEINLINE TList(TList&& InValue) : TList() { Swap(*this, InValue); }
|
||||
|
||||
/** Constructs the container with the contents of the initializer list. */
|
||||
FORCEINLINE TList(initializer_list<FElementType> IL) requires (CCopyConstructible<FElementType>) : TList(Range::Begin(IL), Range::End(IL)) { }
|
||||
FORCEINLINE TList(initializer_list<FElementType> IL) requires (CCopyConstructible<FElementType>) : TList(Ranges::Begin(IL), Ranges::End(IL)) { }
|
||||
|
||||
/** Destructs the list. The destructors of the elements are called and the used storage is deallocated. */
|
||||
~TList()
|
||||
@ -176,9 +176,9 @@ public:
|
||||
TList& operator=(initializer_list<FElementType> IL) requires (CCopyable<FElementType>)
|
||||
{
|
||||
FIterator ThisIter = Begin();
|
||||
const FElementType* OtherIter = Range::Begin(IL);
|
||||
const FElementType* OtherIter = Ranges::Begin(IL);
|
||||
|
||||
while (ThisIter != End() && OtherIter != Range::End(IL))
|
||||
while (ThisIter != End() && OtherIter != Ranges::End(IL))
|
||||
{
|
||||
*ThisIter = *OtherIter;
|
||||
|
||||
@ -188,18 +188,18 @@ public:
|
||||
|
||||
if (ThisIter == End())
|
||||
{
|
||||
while (OtherIter != Range::End(IL))
|
||||
while (OtherIter != Ranges::End(IL))
|
||||
{
|
||||
EmplaceBack(*OtherIter);
|
||||
++OtherIter;
|
||||
}
|
||||
}
|
||||
else if (OtherIter == Range::End(IL))
|
||||
else if (OtherIter == Ranges::End(IL))
|
||||
{
|
||||
Erase(ThisIter, End());
|
||||
}
|
||||
|
||||
Impl.ListNum = Range::Num(IL);
|
||||
Impl.ListNum = Ranges::Num(IL);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -251,7 +251,7 @@ public:
|
||||
/** Inserts 'Count' copies of the 'InValue' before 'Iter' in the container. */
|
||||
FIterator Insert(FConstIterator Iter, size_t Count, const FElementType& InValue) requires (CCopyConstructible<FElementType>)
|
||||
{
|
||||
return Insert(Iter, Range::Repeat(InValue, Count));
|
||||
return Insert(Iter, Ranges::Repeat(InValue, Count));
|
||||
}
|
||||
|
||||
/** Inserts elements from range ['First', 'Last') before 'Iter'. */
|
||||
@ -291,10 +291,10 @@ public:
|
||||
|
||||
/** Inserts elements from range ['First', 'Last') before 'Iter'. */
|
||||
template <CInputRange R> requires (CConstructibleFrom<FElementType, TRangeReference<R>>)
|
||||
FORCEINLINE FIterator Insert(FConstIterator Iter, R&& Range) { return Insert(Iter, Range::Begin(Range), Range::End(Range)); }
|
||||
FORCEINLINE FIterator Insert(FConstIterator Iter, R&& Range) { return Insert(Iter, Ranges::Begin(Range), Ranges::End(Range)); }
|
||||
|
||||
/** Inserts elements from initializer list before 'Iter' in the container. */
|
||||
FORCEINLINE FIterator Insert(FConstIterator Iter, initializer_list<FElementType> IL) requires (CCopyConstructible<FElementType>) { return Insert(Iter, Range::Begin(IL), Range::End(IL)); }
|
||||
FORCEINLINE FIterator Insert(FConstIterator Iter, initializer_list<FElementType> IL) requires (CCopyConstructible<FElementType>) { return Insert(Iter, Ranges::Begin(IL), Ranges::End(IL)); }
|
||||
|
||||
/** Inserts a new element into the container directly before 'Iter'. */
|
||||
template <typename... Ts> requires (CConstructibleFrom<FElementType, Ts...>)
|
||||
|
@ -5,9 +5,9 @@
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/Meta.h"
|
||||
#include "Templates/TypeHash.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/ReverseIterator.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
|
@ -5,9 +5,9 @@
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/TypeHash.h"
|
||||
#include "Templates/Noncopyable.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/ReverseIterator.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/ReverseIterator.h"
|
||||
#include "Iterator/MoveIterator.h"
|
||||
#include "Iterator/CountedIterator.h"
|
||||
#include "Iterator/InsertIterator.h"
|
@ -2,8 +2,8 @@
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
@ -67,14 +67,12 @@ public:
|
||||
}
|
||||
|
||||
template <CInputOrOutputIterator J> requires (CCommonType<I, J>)
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Length == RHS.Length; }
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Num() == RHS.Num(); }
|
||||
|
||||
template <CInputOrOutputIterator J> requires (CCommonType<I, J>)
|
||||
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Length <=> RHS.Length; }
|
||||
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Num() <=> RHS.Num(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(FDefaultSentinel) const& { return Length == static_cast<ptrdiff>(0); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(FDefaultSentinel) const& { return static_cast<ptrdiff>(0) <=> Length; }
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(FDefaultSentinel) const& { return Num() == static_cast<ptrdiff>(0); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() { CheckThis(true); return *GetBase(); }
|
||||
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() const requires (CDereferenceable<const I>) { CheckThis(true); return *GetBase(); }
|
||||
@ -99,7 +97,7 @@ public:
|
||||
NODISCARD friend FORCEINLINE constexpr TCountedIterator operator+(ptrdiff Offset, TCountedIterator Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; }
|
||||
|
||||
template <CInputOrOutputIterator J> requires (CCommonType<I, J>)
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { LHS.CheckThis(); RHS.CheckThis(); return LHS.Length - RHS.Length; }
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return RHS.Num() - LHS.Num(); }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TCountedIterator& LHS, FDefaultSentinel) { LHS.CheckThis(); return -LHS.Num(); }
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(FDefaultSentinel, const TCountedIterator& RHS) { RHS.CheckThis(); return RHS.Num(); }
|
||||
@ -123,9 +121,6 @@ private:
|
||||
checkf(!(bExceptEnd && Length == static_cast<ptrdiff>(0)), TEXT("Read access violation. Please check Num()."));
|
||||
}
|
||||
|
||||
template <CInputOrOutputIterator J>
|
||||
friend class TCountedIterator;
|
||||
|
||||
};
|
||||
|
||||
static_assert( CInputIterator<TCountedIterator< IInputIterator<int&>>>);
|
@ -1,10 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Noncopyable.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/Noncopyable.h"
|
||||
#include "Templates/Invoke.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
@ -122,27 +125,77 @@ private:
|
||||
|
||||
static_assert(COutputIterator<TInsertIterator<void(*)(int)>, int>);
|
||||
|
||||
template <typename C>
|
||||
class FFrontInserter
|
||||
{
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr explicit FFrontInserter(C& InContainer) : Container(AddressOf(InContainer)) { }
|
||||
|
||||
template <typename T>
|
||||
FORCEINLINE constexpr void operator()(T&& A) { Container->PushFront(Forward<T>(A)); }
|
||||
|
||||
private:
|
||||
|
||||
C* Container;
|
||||
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
class FBackInserter
|
||||
{
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr explicit FBackInserter(C& InContainer) : Container(AddressOf(InContainer)) { }
|
||||
|
||||
template <typename T>
|
||||
FORCEINLINE constexpr void operator()(T&& A) { Container->PushBack(Forward<T>(A)); }
|
||||
|
||||
private:
|
||||
|
||||
C* Container;
|
||||
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
class FInserter
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename I>
|
||||
FORCEINLINE constexpr FInserter(C& InContainer, I&& InIter) : Container(AddressOf(InContainer)), Iter(Forward<I>(InIter)) { }
|
||||
|
||||
template <typename T>
|
||||
FORCEINLINE constexpr void operator()(T&& A) { Iter = Container->Insert(Iter, Forward<T>(A)); ++Iter; }
|
||||
|
||||
private:
|
||||
|
||||
C* Container;
|
||||
typename C::FConstIterator Iter;
|
||||
|
||||
};
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
/** Creates an iterator adapter inserted in the front of the container. */
|
||||
template <typename C>
|
||||
NODISCARD FORCEINLINE constexpr auto MakeFrontInserter(C& Container)
|
||||
{
|
||||
return NAMESPACE_PRIVATE::TInsertIterator([&Container]<typename T>(T&& A) { Container.PushFront(Forward<T>(A)); });
|
||||
return NAMESPACE_PRIVATE::TInsertIterator(NAMESPACE_PRIVATE::FFrontInserter(Container));
|
||||
}
|
||||
|
||||
/** Creates an iterator adapter inserted in the back of the container. */
|
||||
template <typename C>
|
||||
NODISCARD FORCEINLINE constexpr auto MakeBackInserter(C& Container)
|
||||
{
|
||||
return NAMESPACE_PRIVATE::TInsertIterator([&Container]<typename T>(T&& A) { Container.PushBack(Forward<T>(A)); });
|
||||
return NAMESPACE_PRIVATE::TInsertIterator(NAMESPACE_PRIVATE::FBackInserter(Container));
|
||||
}
|
||||
|
||||
/** Creates an iterator adapter inserted in the container. */
|
||||
template <typename C>
|
||||
NODISCARD FORCEINLINE constexpr auto MakeInserter(C& Container, const typename C::FConstIterator& InIter)
|
||||
template <typename C, typename I>
|
||||
NODISCARD FORCEINLINE constexpr auto MakeInserter(C& Container, I&& InIter)
|
||||
{
|
||||
return NAMESPACE_PRIVATE::TInsertIterator([&Container, Iter = InIter]<typename T>(T&& A) mutable { Iter = Container.Insert(Iter, Forward<T>(A)); });
|
||||
return NAMESPACE_PRIVATE::TInsertIterator(NAMESPACE_PRIVATE::FInserter(Container, Forward<I>(InIter)));
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
10
Redcraft.Utility/Source/Public/Iterators/Iterators.h
Normal file
10
Redcraft.Utility/Source/Public/Iterators/Iterators.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
#include "Iterators/MoveIterator.h"
|
||||
#include "Iterators/CountedIterator.h"
|
||||
#include "Iterators/InsertIterator.h"
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
@ -47,7 +47,7 @@ public:
|
||||
NODISCARD friend FORCEINLINE constexpr bool operator==(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return LHS.GetBase() == RHS.GetBase(); }
|
||||
|
||||
template <CInputIterator J> requires (CThreeWayComparable<I, J>)
|
||||
NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<I, J> operator<=>(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return RHS.GetBase() <=> LHS.GetBase(); }
|
||||
NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<I, J> operator<=>(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return LHS.GetBase() <=> RHS.GetBase(); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TIteratorRValueReference<I> operator*() const { return MoveTemp(*GetBase()); }
|
||||
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Miscellaneous/Compare.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
@ -63,8 +63,8 @@ public:
|
||||
FORCEINLINE constexpr TReverseIterator& operator+=(ptrdiff Offset) requires (CRandomAccessIterator<I>) { Current -= Offset; return *this; }
|
||||
FORCEINLINE constexpr TReverseIterator& operator-=(ptrdiff Offset) requires (CRandomAccessIterator<I>) { Current += Offset; return *this; }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TReverseIterator operator+(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TReverseIterator Temp = *this; Temp -= Offset; return Temp; }
|
||||
NODISCARD FORCEINLINE constexpr TReverseIterator operator-(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TReverseIterator Temp = *this; Temp += Offset; return Temp; }
|
||||
NODISCARD FORCEINLINE constexpr TReverseIterator operator+(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TReverseIterator Temp = *this; Temp += Offset; return Temp; }
|
||||
NODISCARD FORCEINLINE constexpr TReverseIterator operator-(ptrdiff Offset) const requires (CRandomAccessIterator<I>) { TReverseIterator Temp = *this; Temp -= Offset; return Temp; }
|
||||
|
||||
NODISCARD friend FORCEINLINE constexpr TReverseIterator operator+(ptrdiff Offset, const TReverseIterator& Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; }
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
32
Redcraft.Utility/Source/Public/Miscellaneous/BitwiseEnum.h
Normal file
32
Redcraft.Utility/Source/Public/Miscellaneous/BitwiseEnum.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
#define ENABLE_ENUM_CLASS_BITWISE_OPERATIONS(Enum) \
|
||||
NODISCARD FORCEINLINE constexpr Enum operator| (Enum LHS, Enum RHS) { return static_cast<Enum>(static_cast<TUnderlyingType<Enum>>(LHS) | static_cast<TUnderlyingType<Enum>>(RHS)); } \
|
||||
NODISCARD FORCEINLINE constexpr Enum operator& (Enum LHS, Enum RHS) { return static_cast<Enum>(static_cast<TUnderlyingType<Enum>>(LHS) & static_cast<TUnderlyingType<Enum>>(RHS)); } \
|
||||
NODISCARD FORCEINLINE constexpr Enum operator^ (Enum LHS, Enum RHS) { return static_cast<Enum>(static_cast<TUnderlyingType<Enum>>(LHS) ^ static_cast<TUnderlyingType<Enum>>(RHS)); } \
|
||||
FORCEINLINE constexpr Enum& operator|=(Enum& LHS, Enum RHS) { LHS = LHS | RHS; return LHS; } \
|
||||
FORCEINLINE constexpr Enum& operator&=(Enum& LHS, Enum RHS) { LHS = LHS & RHS; return LHS; } \
|
||||
FORCEINLINE constexpr Enum& operator^=(Enum& LHS, Enum RHS) { LHS = LHS ^ RHS; return LHS; } \
|
||||
NODISCARD FORCEINLINE constexpr bool operator! (Enum E ) { return !static_cast<TUnderlyingType<Enum>>(E); } \
|
||||
NODISCARD FORCEINLINE constexpr Enum operator~ (Enum E ) { return static_cast<Enum>(~static_cast<TUnderlyingType<Enum>>(E)); }
|
||||
|
||||
#define FRIEND_ENUM_CLASS_BITWISE_OPERATIONS(Enum) \
|
||||
friend constexpr Enum operator| (Enum , Enum); \
|
||||
friend constexpr Enum operator& (Enum , Enum); \
|
||||
friend constexpr Enum operator^ (Enum , Enum); \
|
||||
friend constexpr Enum& operator|=(Enum&, Enum); \
|
||||
friend constexpr Enum& operator&=(Enum&, Enum); \
|
||||
friend constexpr Enum& operator^=(Enum&, Enum); \
|
||||
friend constexpr bool operator! (Enum ); \
|
||||
friend constexpr Enum operator~ (Enum );
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
217
Redcraft.Utility/Source/Public/Miscellaneous/Console.h
Normal file
217
Redcraft.Utility/Source/Public/Miscellaneous/Console.h
Normal file
@ -0,0 +1,217 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Strings/Formatting.h"
|
||||
#include "Strings/StringView.h"
|
||||
#include "Strings/String.h"
|
||||
#include "Miscellaneous/BitwiseEnum.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
/** An enumeration that defines the color of the console. */
|
||||
enum class EColor : uint8
|
||||
{
|
||||
Default = 0xFF,
|
||||
|
||||
Black = 0b0000,
|
||||
Red = 0b0001,
|
||||
Green = 0b0010,
|
||||
Blue = 0b0100,
|
||||
Intensity = 0b1000,
|
||||
|
||||
Cyan = Green | Blue,
|
||||
Magenta = Blue | Red,
|
||||
Yellow = Red | Green,
|
||||
|
||||
White = Red | Green | Blue,
|
||||
|
||||
BrightBlack = Intensity | Black,
|
||||
BrightRed = Intensity | Red,
|
||||
BrightGreen = Intensity | Green,
|
||||
BrightBlue = Intensity | Blue,
|
||||
BrightYellow = Intensity | Yellow,
|
||||
BrightMagenta = Intensity | Magenta,
|
||||
BrightCyan = Intensity | Cyan,
|
||||
BrightWhite = Intensity | White
|
||||
};
|
||||
|
||||
ENABLE_ENUM_CLASS_BITWISE_OPERATIONS(EColor)
|
||||
|
||||
/** @return The color of the console. */
|
||||
NODISCARD REDCRAFTUTILITY_API EColor GetForegroundColor();
|
||||
NODISCARD REDCRAFTUTILITY_API EColor GetBackgroundColor();
|
||||
|
||||
/** Set the color of the console. Returns the color that was successfully set. */
|
||||
REDCRAFTUTILITY_API EColor SetForegroundColor(EColor InColor);
|
||||
REDCRAFTUTILITY_API EColor SetBackgroundColor(EColor InColor);
|
||||
|
||||
/** @return The size of the console window. */
|
||||
NODISCARD REDCRAFTUTILITY_API uint GetWindowWidth();
|
||||
NODISCARD REDCRAFTUTILITY_API uint GetWindowHeight();
|
||||
|
||||
/** @return true if the standard stream is redirected. */
|
||||
NODISCARD REDCRAFTUTILITY_API bool IsInputRedirected();
|
||||
NODISCARD REDCRAFTUTILITY_API bool IsOutputRedirected();
|
||||
NODISCARD REDCRAFTUTILITY_API bool IsErrorRedirected();
|
||||
|
||||
/** Clear the console screen. */
|
||||
REDCRAFTUTILITY_API void Clear();
|
||||
|
||||
/** @return The input character from the standard input. */
|
||||
NODISCARD REDCRAFTUTILITY_API char Input(bool bEcho = true);
|
||||
|
||||
/** @return The input line from the standard input. */
|
||||
NODISCARD REDCRAFTUTILITY_API FString InputLn(bool bEcho = true);
|
||||
|
||||
/** Print the character to the standard output. */
|
||||
REDCRAFTUTILITY_API bool Print(char Char);
|
||||
|
||||
/** Print the formatted string to the standard output. */
|
||||
template <CFormattable... Ts>
|
||||
FORCEINLINE bool Print(FStringView Fmt, Ts&&... Args)
|
||||
{
|
||||
struct FStandardOutputIterator
|
||||
{
|
||||
FORCEINLINE constexpr FStandardOutputIterator& operator=(char Char)
|
||||
{
|
||||
bError |= !Print(Char);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FORCEINLINE constexpr bool operator==(FDefaultSentinel) const { return bError; }
|
||||
|
||||
FORCEINLINE constexpr FStandardOutputIterator& operator*() { return *this; }
|
||||
FORCEINLINE constexpr FStandardOutputIterator& operator++() { return *this; }
|
||||
FORCEINLINE constexpr FStandardOutputIterator& operator++(int) { return *this; }
|
||||
|
||||
bool bError = false;
|
||||
};
|
||||
|
||||
static_assert(COutputIterator<FStandardOutputIterator, char>);
|
||||
|
||||
FStandardOutputIterator Iter;
|
||||
|
||||
auto Range = Ranges::View(Iter, DefaultSentinel);
|
||||
|
||||
Iter = Algorithms::Format(Range, Fmt, Forward<Ts>(Args)...);
|
||||
|
||||
return Iter != DefaultSentinel;
|
||||
}
|
||||
|
||||
/** Print the value to the standard output. */
|
||||
template <CFormattable T>
|
||||
FORCEINLINE bool Print(T&& Value)
|
||||
{
|
||||
if constexpr (CSameAs<TRemoveCVRef<T>, char>)
|
||||
{
|
||||
return Print(static_cast<char>(Value));
|
||||
}
|
||||
|
||||
else if constexpr (CConvertibleTo<T, FStringView>)
|
||||
{
|
||||
return Print(static_cast<FStringView>(Value));
|
||||
}
|
||||
|
||||
else return Print(TEXT("{0}"), Forward<T>(Value));
|
||||
}
|
||||
|
||||
/** Print the newline character to the standard output. */
|
||||
FORCEINLINE bool PrintLn()
|
||||
{
|
||||
return Print(TEXT("\n"));
|
||||
}
|
||||
|
||||
/** Print the string to the standard output and append the newline character. */
|
||||
template <CFormattable... Ts>
|
||||
FORCEINLINE bool PrintLn(FStringView Fmt, Ts&&... Args)
|
||||
{
|
||||
return Print(Fmt, Forward<Ts>(Args)...) && Print(TEXT("\n"));
|
||||
}
|
||||
|
||||
/** Print the value to the standard output and append the newline character. */
|
||||
template <CFormattable T>
|
||||
FORCEINLINE bool PrintLn(T&& Value)
|
||||
{
|
||||
return Print(Forward<T>(Value)) && Print(TEXT("\n"));
|
||||
}
|
||||
|
||||
/** Print the character to the standard error. */
|
||||
REDCRAFTUTILITY_API bool Error(char Char);
|
||||
|
||||
/** Print the formatted string to the standard error. */
|
||||
template <CFormattable... Ts>
|
||||
FORCEINLINE bool Error(FStringView Fmt, Ts&&... Args)
|
||||
{
|
||||
struct FStandardOutputIterator
|
||||
{
|
||||
FORCEINLINE constexpr FStandardOutputIterator& operator=(char Char)
|
||||
{
|
||||
bError |= !Error(Char);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FORCEINLINE constexpr bool operator==(FDefaultSentinel) const { return bError; }
|
||||
|
||||
FORCEINLINE constexpr FStandardOutputIterator& operator*() { return *this; }
|
||||
FORCEINLINE constexpr FStandardOutputIterator& operator++() { return *this; }
|
||||
FORCEINLINE constexpr FStandardOutputIterator& operator++(int) { return *this; }
|
||||
|
||||
bool bError = false;
|
||||
};
|
||||
|
||||
static_assert(COutputIterator<FStandardOutputIterator, char>);
|
||||
|
||||
FStandardOutputIterator Iter;
|
||||
|
||||
auto Range = Ranges::View(Iter, DefaultSentinel);
|
||||
|
||||
Iter = Algorithms::Format(Range, Fmt, Forward<Ts>(Args)...);
|
||||
|
||||
return Iter != DefaultSentinel;
|
||||
}
|
||||
|
||||
/** Print the value to the standard error. */
|
||||
template <CFormattable T>
|
||||
FORCEINLINE bool Error(T&& Value)
|
||||
{
|
||||
if constexpr (CSameAs<TRemoveCVRef<T>, char>)
|
||||
{
|
||||
return Error(static_cast<char>(Value));
|
||||
}
|
||||
|
||||
else if constexpr (CConvertibleTo<T, FStringView>)
|
||||
{
|
||||
return Error(static_cast<FStringView>(Value));
|
||||
}
|
||||
|
||||
else return Error(TEXT("{0}"), Forward<T>(Value));
|
||||
}
|
||||
|
||||
/** Print the newline character to the standard error. */
|
||||
FORCEINLINE bool ErrorLn()
|
||||
{
|
||||
return Error(TEXT("\n"));
|
||||
}
|
||||
|
||||
/** Print the string to the standard error and append the newline character. */
|
||||
template <CFormattable... Ts>
|
||||
FORCEINLINE bool ErrorLn(FStringView Fmt, Ts&&... Args)
|
||||
{
|
||||
return Error(Fmt, Forward<Ts>(Args)...) && Error(TEXT("\n"));
|
||||
}
|
||||
|
||||
/** Print the value to the standard error and append the newline character. */
|
||||
template <CFormattable T>
|
||||
FORCEINLINE bool ErrorLn(T&& Value)
|
||||
{
|
||||
return Error(Forward<T>(Value)) && Error(TEXT("\n"));
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
116
Redcraft.Utility/Source/Public/Miscellaneous/FileSystem.h
Normal file
116
Redcraft.Utility/Source/Public/Miscellaneous/FileSystem.h
Normal file
@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/Function.h"
|
||||
#include "Containers/Array.h"
|
||||
#include "Strings/StringView.h"
|
||||
#include "Strings/String.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(FileSystem)
|
||||
|
||||
/** The encoding of the text file. */
|
||||
enum class EEncoding : uint8
|
||||
{
|
||||
Default,
|
||||
Narrow,
|
||||
Wide,
|
||||
UTF8,
|
||||
UTF16BE,
|
||||
UTF16LE,
|
||||
UTF32BE,
|
||||
UTF32LE,
|
||||
};
|
||||
|
||||
/** Loads the file at the specified path into the byte array. */
|
||||
REDCRAFTUTILITY_API bool LoadFileToArray(TArray<uint8>& Result, FStringView Path);
|
||||
|
||||
/** Saves the byte array to the file at the specified path. */
|
||||
REDCRAFTUTILITY_API bool SaveArrayToFile(TArrayView<const uint8> Data, FStringView Path);
|
||||
|
||||
/**
|
||||
* Loads the file at the specified path into the string.
|
||||
*
|
||||
* @param Result - The string to load the file into.
|
||||
* @param Path - The path to the file to load.
|
||||
* @param Encoding - The encoding of the file. The default value indicates automatic detection.
|
||||
* @param bVerify - Whether to verify the character validity of the file.
|
||||
*
|
||||
* @return true if the file was successfully loaded, false otherwise.
|
||||
*/
|
||||
template <CCharType T>
|
||||
REDCRAFTUTILITY_API bool LoadFileToString(TString<T>& Result, FStringView Path, FileSystem::EEncoding Encoding = FileSystem::EEncoding::Default, bool bVerify = false);
|
||||
|
||||
/**
|
||||
* Saves the string to the file at the specified path.
|
||||
*
|
||||
* @param String - The string to save to the file.
|
||||
* @param Path - The path to the file to save.
|
||||
* @param Encoding - The encoding of the file. The default value indicates the same as the string.
|
||||
* @param bWithBOM - Whether to write the BOM character at the beginning of the file. Not valid for narrow and wide encoding.
|
||||
*
|
||||
* @return true if the file was successfully saved, false otherwise.
|
||||
*/
|
||||
template <CCharType T>
|
||||
REDCRAFTUTILITY_API bool SaveStringToFile(TStringView<T> String, FStringView Path, FileSystem::EEncoding Encoding = FileSystem::EEncoding::Default, bool bWithBOM = true);
|
||||
|
||||
/**
|
||||
* Saves the string to the file at the specified path.
|
||||
*
|
||||
* @param String - The string to save to the file.
|
||||
* @param Path - The path to the file to save.
|
||||
* @param Encoding - The encoding of the file. The default value indicates the same as the string.
|
||||
* @param bWithBOM - Whether to write the BOM character at the beginning of the file. Not valid for narrow and wide encoding.
|
||||
*
|
||||
* @return true if the file was successfully saved, false otherwise.
|
||||
*/
|
||||
template <typename T> requires (CConvertibleTo<T&&, FStringView> || CConvertibleTo<T&&, FWStringView>
|
||||
|| CConvertibleTo<T&&, FU8StringView> || CConvertibleTo<T&&, FU16StringView> || CConvertibleTo<T&&, FU32StringView>)
|
||||
bool SaveStringToFile(T&& String, FStringView Path, FileSystem::EEncoding Encoding = FileSystem::EEncoding::Default, bool bWithBOM = true)
|
||||
{
|
||||
if constexpr (CConvertibleTo<T&&, FStringView>) return SaveStringToFile(FStringView (Forward<T>(String)), Path, Encoding, bWithBOM);
|
||||
else if constexpr (CConvertibleTo<T&&, FWStringView>) return SaveStringToFile(FWStringView (Forward<T>(String)), Path, Encoding, bWithBOM);
|
||||
else if constexpr (CConvertibleTo<T&&, FU8StringView>) return SaveStringToFile(FU8StringView (Forward<T>(String)), Path, Encoding, bWithBOM);
|
||||
else if constexpr (CConvertibleTo<T&&, FU16StringView>) return SaveStringToFile(FU16StringView(Forward<T>(String)), Path, Encoding, bWithBOM);
|
||||
else if constexpr (CConvertibleTo<T&&, FU32StringView>) return SaveStringToFile(FU32StringView(Forward<T>(String)), Path, Encoding, bWithBOM);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @return The size of the file at the specified path. */
|
||||
REDCRAFTUTILITY_API size_t FileSize(FStringView Path);
|
||||
|
||||
/** Deletes the file at the specified path. */
|
||||
REDCRAFTUTILITY_API bool Delete(FStringView Path);
|
||||
|
||||
/** @return true if the regular file at the specified path exists, false otherwise. */
|
||||
REDCRAFTUTILITY_API bool Exists(FStringView Path);
|
||||
|
||||
/** Copies the file from the source path to the destination path. */
|
||||
REDCRAFTUTILITY_API bool Copy(FStringView Destination, FStringView Source);
|
||||
|
||||
/** Renames the file from the source path to the destination path. */
|
||||
REDCRAFTUTILITY_API bool Rename(FStringView Destination, FStringView Source);
|
||||
|
||||
/** Creates the directory at the specified path. If recursive, it will not delete the created items on failure. */
|
||||
REDCRAFTUTILITY_API bool CreateDirectory(FStringView Path, bool bRecursive = false);
|
||||
|
||||
/** Deletes the directory at the specified path. If recursive, it will not recreate the deleted items on failure. */
|
||||
REDCRAFTUTILITY_API bool DeleteDirectory(FStringView Path, bool bRecursive = false);
|
||||
|
||||
/** @return true if the directory at the specified path exists, false otherwise. */
|
||||
REDCRAFTUTILITY_API bool ExistsDirectory(FStringView Path);
|
||||
|
||||
/** Iterates items in the directory at the specified path. */
|
||||
REDCRAFTUTILITY_API bool IterateDirectory(FStringView Path, TFunctionRef<bool(FStringView /* Path */, bool /* bIsDirectory */)> Visitor);
|
||||
|
||||
NAMESPACE_END(FileSystem)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -36,7 +36,7 @@ NAMESPACE_PRIVATE_END
|
||||
#define VARARGS_ACCESS_COPY(ContextName, ContextSource) NAMESPACE_STD::va_list ContextName; va_copy(ContextName, ContextSource)
|
||||
|
||||
/** Accesses the next variadic function argument. */
|
||||
#define VARARGS_ACCESS(ContextName, Type) (NAMESPACE_PRIVATE::VarArgsAssert<Type>, va_arg(ContextName, Type))
|
||||
#define VARARGS_ACCESS(ContextName, Type) (NAMESPACE_REDCRAFT::NAMESPACE_PRIVATE::VarArgsAssert<Type>, va_arg(ContextName, Type))
|
||||
|
||||
/** Ends traversal of the variadic function arguments. */
|
||||
#define VARARGS_ACCESS_END(ContextName) va_end(ContextName)
|
||||
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Numeric/Literal.h"
|
||||
#include "Numeric/Limits.h"
|
||||
#include "Numeric/Numbers.h"
|
||||
#include "Numeric/Bit.h"
|
||||
#include "Numeric/Math.h"
|
||||
#include "Numeric/Random.h"
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Numeric/Limits.h"
|
||||
#include "Numeric/Literal.h"
|
||||
#include "Numerics/Limits.h"
|
||||
#include "Numerics/Literals.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
#include <bit>
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Numeric/Bit.h"
|
||||
#include "Numeric/Limits.h"
|
||||
#include "Numeric/Numbers.h"
|
||||
#include "Numerics/Bit.h"
|
||||
#include "Numerics/Limits.h"
|
||||
#include "Numerics/Numbers.h"
|
||||
#include "Templates/Tuple.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
9
Redcraft.Utility/Source/Public/Numerics/Numerics.h
Normal file
9
Redcraft.Utility/Source/Public/Numerics/Numerics.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Numerics/Literals.h"
|
||||
#include "Numerics/Limits.h"
|
||||
#include "Numerics/Numbers.h"
|
||||
#include "Numerics/Bit.h"
|
||||
#include "Numerics/Math.h"
|
||||
#include "Numerics/Random.h"
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Numeric/Bit.h"
|
||||
#include "Numeric/Math.h"
|
||||
#include "Numerics/Bit.h"
|
||||
#include "Numerics/Math.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Range/View.h"
|
||||
#include "Range/Conversion.h"
|
||||
#include "Range/Factory.h"
|
||||
#include "Range/Pipe.h"
|
||||
#include "Range/AllView.h"
|
||||
#include "Range/MoveView.h"
|
||||
#include "Range/FilterView.h"
|
||||
#include "Range/TransformView.h"
|
||||
#include "Range/TakeView.h"
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Range/View.h"
|
||||
#include "Range/Pipe.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
@ -11,7 +11,7 @@ NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/**
|
||||
* A view adapter that references other range.
|
||||
@ -31,12 +31,12 @@ public:
|
||||
template <typename T> requires (!CSameAs<TRemoveCVRef<T>, TRefView> && CConvertibleTo<T, R&> && requires { Func(DeclVal<T>()); })
|
||||
FORCEINLINE constexpr TRefView(T&& InRange) : Ptr(AddressOf(static_cast<R&>(Forward<T>(InRange)))) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TRangeIterator<R> Begin() const { return Range::Begin(*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr TRangeSentinel<R> End() const { return Range::End (*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr TRangeIterator<R> Begin() const { return Ranges::Begin(*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr TRangeSentinel<R> End() const { return Ranges::End (*Ptr); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousRange<R>) { return Range::GetData(*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<R>) { return Range::Num (*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (requires(R Range) { Range::IsEmpty(Range); }) { return Range::IsEmpty(*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousRange<R>) { return Ranges::GetData(*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<R>) { return Ranges::Num (*Ptr); }
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (requires(R Range) { Ranges::IsEmpty(Range); }) { return Ranges::IsEmpty(*Ptr); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr R& GetBase() const { return *Ptr; }
|
||||
|
||||
@ -61,12 +61,12 @@ static_assert( CView<TRefView< IRange<IInputOrOutputIterator<int>>>>)
|
||||
|
||||
static_assert(COutputRange<TRefView<IRange<IOutputIterator<int&>>>, int>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
template <typename T>
|
||||
constexpr bool bEnableBorrowedRange<Range::TRefView<T>> = true;
|
||||
constexpr bool bEnableBorrowedRange<Ranges::TRefView<T>> = true;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/**
|
||||
* A view adapter that has unique ownership of a range.
|
||||
@ -88,19 +88,19 @@ public:
|
||||
FORCEINLINE constexpr TOwningView& operator=(const TOwningView&) = delete;
|
||||
FORCEINLINE constexpr TOwningView& operator=(TOwningView&&) = default;
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() { return Range::Begin(Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto End() { return Range::End (Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const R>) { return Range::Begin(Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const R>) { return Range::End (Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() { return Ranges::Begin(Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto End() { return Ranges::End (Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const R>) { return Ranges::Begin(Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const R>) { return Ranges::End (Base); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() requires (CContiguousRange< R>) { return Range::GetData(Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousRange<const R>) { return Range::GetData(Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() requires (CContiguousRange< R>) { return Ranges::GetData(Base); }
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousRange<const R>) { return Ranges::GetData(Base); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< R>) { return Range::Num(Base); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<const R>) { return Range::Num(Base); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< R>) { return Ranges::Num(Base); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<const R>) { return Ranges::Num(Base); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() requires (requires( R Base) { Range::IsEmpty(Base); }) { return Range::IsEmpty(Base); }
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (requires(const R Base) { Range::IsEmpty(Base); }) { return Range::IsEmpty(Base); }
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() requires (requires( R Base) { Ranges::IsEmpty(Base); }) { return Ranges::IsEmpty(Base); }
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (requires(const R Base) { Ranges::IsEmpty(Base); }) { return Ranges::IsEmpty(Base); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr R& GetBase() & { return Base; }
|
||||
NODISCARD FORCEINLINE constexpr R&& GetBase() && { return MoveTemp(Base); }
|
||||
@ -125,12 +125,12 @@ static_assert( CView<TOwningView< IRange<IInputOrOutputIterator<int>>
|
||||
|
||||
static_assert(COutputRange<TOwningView<IRange<IOutputIterator<int&>>>, int>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
template <typename T>
|
||||
constexpr bool bEnableBorrowedRange<Range::TOwningView<T>> = bEnableBorrowedRange<T>;
|
||||
constexpr bool bEnableBorrowedRange<Ranges::TOwningView<T>> = bEnableBorrowedRange<T>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** Creates A view adapter that includes all elements of a range. */
|
||||
template <CViewableRange R>
|
||||
@ -152,9 +152,9 @@ NODISCARD FORCEINLINE constexpr auto All(R&& InRange)
|
||||
/** Creates A view adapter that includes all elements of a range. */
|
||||
NODISCARD FORCEINLINE constexpr auto All()
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R> requires (requires { Range::All(DeclVal<R>()); }) (R&& Base)
|
||||
using FClosure = decltype([]<CViewableRange R> requires (requires { Ranges::All(DeclVal<R>()); }) (R&& Base)
|
||||
{
|
||||
return Range::All(Forward<R>(Base));
|
||||
return Ranges::All(Forward<R>(Base));
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure>();
|
||||
@ -162,7 +162,7 @@ NODISCARD FORCEINLINE constexpr auto All()
|
||||
|
||||
/** A view adapter that includes all elements of a range. */
|
||||
template <CViewableRange R>
|
||||
using TAllView = decltype(Range::All(DeclVal<R>()));
|
||||
using TAllView = decltype(Ranges::All(DeclVal<R>()));
|
||||
|
||||
static_assert( CInputRange<TAllView<IRange< IInputIterator<int&>>>>);
|
||||
static_assert( CForwardRange<TAllView<IRange< IForwardIterator<int&>>>>);
|
||||
@ -176,7 +176,7 @@ static_assert( CView<TAllView< IRange<IInputOrOutputIterator<int>>>>)
|
||||
|
||||
static_assert(COutputRange<TAllView<IRange<IOutputIterator<int&>>>, int>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Range/View.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Range/AllView.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/AllView.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Range/TransformView.h"
|
||||
#include "Ranges/TransformView.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
@ -32,24 +32,49 @@ concept CReservableContainer = CSizedRange<C>
|
||||
&& requires (C& Container, size_t N)
|
||||
{
|
||||
Container.Reserve(N);
|
||||
{ Container.Num() } -> CSameAs<size_t>;
|
||||
{ Container.Max() } -> CSameAs<size_t>;
|
||||
};
|
||||
|
||||
/** A concept specifies a container that can append elements. */
|
||||
template <typename C, typename Ref>
|
||||
template <typename C, typename T>
|
||||
concept CAppendableContainer =
|
||||
requires (C& Container, Ref&& Reference)
|
||||
requires (C& Container, T&& Object)
|
||||
{
|
||||
requires
|
||||
(
|
||||
requires { Container.EmplaceBack (Forward<Ref>(Reference)); } ||
|
||||
requires { Container.PushBack (Forward<Ref>(Reference)); } ||
|
||||
requires { Container.Emplace(Container.End(), Forward<Ref>(Reference)); } ||
|
||||
requires { Container.Insert (Container.End(), Forward<Ref>(Reference)); }
|
||||
requires { Container.EmplaceBack (Forward<T>(Object)); } ||
|
||||
requires { Container.PushBack (Forward<T>(Object)); } ||
|
||||
requires { Container.Emplace(Container.End(), Forward<T>(Object)); } ||
|
||||
requires { Container.Insert (Container.End(), Forward<T>(Object)); }
|
||||
);
|
||||
};
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
template <typename T, CAppendableContainer<T> C>
|
||||
FORCEINLINE constexpr void AppendTo(C& Container, T&& Object)
|
||||
{
|
||||
if constexpr (requires { Container.EmplaceBack(Forward<T>(Object)); })
|
||||
{
|
||||
Container.EmplaceBack(Forward<T>(Object));
|
||||
}
|
||||
|
||||
else if constexpr (requires { Container.PushBack(Forward<T>(Object)); })
|
||||
{
|
||||
Container.PushBack(Forward<T>(Object));
|
||||
}
|
||||
|
||||
else if constexpr (requires { Container.Emplace(Container.End(), Forward<T>(Object)); })
|
||||
{
|
||||
Container.Emplace(Container.End(), Forward<T>(Object));
|
||||
}
|
||||
|
||||
else /* if constexpr (requires { Container.Insert(Container.End(), Forward<T>(Object)); }) */
|
||||
{
|
||||
Container.Insert(Container.End(), Forward<T>(Object));
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructs a non-view object from the elements of the range. */
|
||||
template <typename C, CInputRange R, typename... Ts> requires (!CView<C>)
|
||||
@ -64,7 +89,7 @@ NODISCARD FORCEINLINE constexpr auto To(R&& Range, Ts&&... Args)
|
||||
|
||||
else if constexpr (CCommonRange<R> && CInputRange<R> && CConstructibleFrom<C, TRangeIterator<R>, TRangeSentinel<R>, Ts...>)
|
||||
{
|
||||
return C(Range::Begin(Range), Range::End(Range), Forward<Ts>(Args)...);
|
||||
return C(Ranges::Begin(Range), Ranges::End(Range), Forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
else if constexpr (CConstructibleFrom<C, Ts...> && CAppendableContainer<C, TRangeReference<R>>)
|
||||
@ -73,30 +98,12 @@ NODISCARD FORCEINLINE constexpr auto To(R&& Range, Ts&&... Args)
|
||||
|
||||
if constexpr (CSizedRange<R> && CReservableContainer<C>)
|
||||
{
|
||||
Result.Reserve(Range::Num(Range));
|
||||
Result.Reserve(Ranges::Num(Range));
|
||||
}
|
||||
|
||||
for (TRangeReference<R> Element : Range)
|
||||
{
|
||||
if constexpr (requires { Result.EmplaceBack(DeclVal<TRangeReference<R>>()); })
|
||||
{
|
||||
Result.EmplaceBack(Forward<TRangeReference<R>>(Element));
|
||||
}
|
||||
|
||||
else if constexpr (requires { Result.PushBack(DeclVal<TRangeReference<R>>()); })
|
||||
{
|
||||
Result.PushBack(Forward<TRangeReference<R>>(Element));
|
||||
}
|
||||
|
||||
else if constexpr (requires { Result.Emplace(Result.End(), DeclVal<TRangeReference<R>>()); })
|
||||
{
|
||||
Result.Emplace(Result.End(), Forward<TRangeReference<R>>(Element));
|
||||
}
|
||||
|
||||
else /* if constexpr (requires { Result.Insert(Result.End(), DeclVal<TRangeReference<R>>()); }) */
|
||||
{
|
||||
Result.Insert(Result.End(), Forward<TRangeReference<R>>(Element));
|
||||
}
|
||||
Ranges::AppendTo(Result, Forward<TRangeReference<R>>(Element));
|
||||
}
|
||||
|
||||
return Result;
|
||||
@ -108,7 +115,7 @@ NODISCARD FORCEINLINE constexpr auto To(R&& Range, Ts&&... Args)
|
||||
{
|
||||
if constexpr (CInputRange<TRangeReference<C>>)
|
||||
{
|
||||
return Range::To<C>(Range::All(Range) | Range::Transform([]<typename T>(T&& Element) { return Range::To<TRangeElement<C>>(Forward<T>(Element)); }), Forward<Args>(Args)...);
|
||||
return Ranges::To<C>(Ranges::All(Range) | Ranges::Transform([]<typename T>(T&& Element) { return Ranges::To<TRangeElement<C>>(Forward<T>(Element)); }), Forward<Args>(Args)...);
|
||||
}
|
||||
|
||||
else static_assert(sizeof(R) == -1, "The container type is not constructible from a range");
|
||||
@ -121,12 +128,12 @@ NODISCARD FORCEINLINE constexpr auto To(R&& Range, Ts&&... Args)
|
||||
{
|
||||
if constexpr (requires { C(DeclVal<R>(), DeclVal<Ts>()...); })
|
||||
{
|
||||
return Range::To<decltype(C(DeclVal<R>(), DeclVal<Ts>()...))>(Forward<R>(Range), Forward<Ts>(Args)...);
|
||||
return Ranges::To<decltype(C(DeclVal<R>(), DeclVal<Ts>()...))>(Forward<R>(Range), Forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
else if constexpr (requires { C(DeclVal<TRangeIterator<R>>(), DeclVal<TRangeSentinel<R>>(), DeclVal<Args>()...); })
|
||||
{
|
||||
return Range::To<decltype(C(DeclVal<TRangeIterator<R>>(), DeclVal<TRangeSentinel<R>>(), DeclVal<Args>()...))>(Forward<R>(Range), Forward<Ts>(Args)...);
|
||||
return Ranges::To<decltype(C(DeclVal<TRangeIterator<R>>(), DeclVal<TRangeSentinel<R>>(), DeclVal<Args>()...))>(Forward<R>(Range), Forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
else static_assert(sizeof(R) == -1, "The container type is not constructible from a range");
|
||||
@ -136,9 +143,9 @@ NODISCARD FORCEINLINE constexpr auto To(R&& Range, Ts&&... Args)
|
||||
template <typename C, typename... Ts> requires (!CView<C>)
|
||||
NODISCARD FORCEINLINE constexpr auto To(Ts&&... Args)
|
||||
{
|
||||
using FClosure = decltype([]<CInputRange R, typename... Us> requires (requires { Range::To<C>(DeclVal<R>(), DeclVal<Us>()...); }) (R&& Range, Us&&... Args)
|
||||
using FClosure = decltype([]<CInputRange R, typename... Us> requires (requires { Ranges::To<C>(DeclVal<R>(), DeclVal<Us>()...); }) (R&& Range, Us&&... Args)
|
||||
{
|
||||
return Range::To<C>(Forward<R>(Range), Forward<Us>(Args)...);
|
||||
return Ranges::To<C>(Forward<R>(Range), Forward<Us>(Args)...);
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, TDecay<Ts>...>(Forward<Ts>(Args)...);
|
||||
@ -148,15 +155,15 @@ NODISCARD FORCEINLINE constexpr auto To(Ts&&... Args)
|
||||
template <template <typename...> typename C, typename... Ts>
|
||||
NODISCARD FORCEINLINE constexpr auto To(Ts&&... Args)
|
||||
{
|
||||
using FClosure = decltype([]<CInputRange R, typename... Us> requires (requires { Range::To<C>(DeclVal<R>(), DeclVal<Us>()...); }) (R&& Range, Us&&... Args)
|
||||
using FClosure = decltype([]<CInputRange R, typename... Us> requires (requires { Ranges::To<C>(DeclVal<R>(), DeclVal<Us>()...); }) (R&& Range, Us&&... Args)
|
||||
{
|
||||
return Range::To<C>(Forward<R>(Range), Forward<Us>(Args)...);
|
||||
return Ranges::To<C>(Forward<R>(Range), Forward<Us>(Args)...);
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, TDecay<Ts>...>(Forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Range/View.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
@ -11,7 +11,7 @@ NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** A view type that produces a view of no elements of a particular type. */
|
||||
template <CObject T>
|
||||
@ -39,12 +39,12 @@ static_assert( CCommonRange<TEmptyView<int>>);
|
||||
static_assert( CSizedRange<TEmptyView<int>>);
|
||||
static_assert( CView<TEmptyView<int>>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
template <typename T>
|
||||
constexpr bool bEnableBorrowedRange<Range::TEmptyView<T>> = true;
|
||||
constexpr bool bEnableBorrowedRange<Ranges::TEmptyView<T>> = true;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** A view type that contains exactly one element of a specified value. */
|
||||
template <CObject T> requires (CMoveConstructible<T>)
|
||||
@ -190,12 +190,12 @@ TIotaView(T, U) -> TIotaView<T, U>;
|
||||
static_assert(CForwardRange<TIotaView<int>>);
|
||||
static_assert( CView<TIotaView<int>>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
template <typename T, typename U>
|
||||
constexpr bool bEnableBorrowedRange<Range::TIotaView<T, U>> = true;
|
||||
constexpr bool bEnableBorrowedRange<Ranges::TIotaView<T, U>> = true;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** A view type that generates a sequence of elements by repeatedly producing the same value. Can be either bounded or unbounded. */
|
||||
template <CObject W, bool bIsUnreachable = true> requires (CMoveConstructible<W> && CSameAs<W, TRemoveCV<W>>)
|
||||
@ -307,9 +307,9 @@ static_assert( CCommonRange<TRepeatView<int, false>>);
|
||||
static_assert( CSizedRange<TRepeatView<int, false>>);
|
||||
static_assert( CView<TRepeatView<int, false>>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** A view of no elements of a particular type. */
|
||||
template <CObject T>
|
||||
@ -350,7 +350,7 @@ NODISCARD FORCEINLINE constexpr TRepeatView<TDecay<W>, false> Repeat(W&& Value,
|
||||
return TRepeatView<TDecay<W>, false>(Forward<W>(Value), Count);
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
@ -4,19 +4,19 @@
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/Invoke.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Range/Pipe.h"
|
||||
#include "Range/View.h"
|
||||
#include "Range/AllView.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/AllView.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/**
|
||||
* A view adapter that consists of the elements of a range that satisfies a predicate.
|
||||
@ -46,7 +46,7 @@ public:
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FIterator Begin()
|
||||
{
|
||||
FIterator Iter(*this, Range::Begin(Base));
|
||||
FIterator Iter(*this, Ranges::Begin(Base));
|
||||
|
||||
do
|
||||
{
|
||||
@ -63,7 +63,7 @@ public:
|
||||
return Iter;
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr FSentinel End() { return FSentinel(*this, Range::End(Base)); }
|
||||
NODISCARD FORCEINLINE constexpr FSentinel End() { return FSentinel(*this, Ranges::End(Base)); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible<V>) { return Base; }
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() && { return MoveTemp(Base); }
|
||||
@ -161,9 +161,9 @@ static_assert(CBidirectionalRange<TFilterView<TAllView<IRange< IContiguousIter
|
||||
static_assert(CCommonRange<TFilterView<TAllView<ICommonRange<IForwardIterator<int>>>, bool(*)(int)>>);
|
||||
static_assert( CView<TFilterView<TAllView< IRange< IInputIterator<int>>>, bool(*)(int)>>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** Creates A view adapter that consists of the elements of a range that satisfies a predicate. */
|
||||
template <CViewableRange R, typename Pred> requires (requires { TFilterView(DeclVal<R>(), DeclVal<Pred>()); })
|
||||
@ -176,15 +176,15 @@ NODISCARD FORCEINLINE constexpr auto Filter(R&& Base, Pred&& Predicate)
|
||||
template <typename Pred>
|
||||
NODISCARD FORCEINLINE constexpr auto Filter(Pred&& Predicate)
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R, typename T> requires (requires { Range::Filter(DeclVal<R>(), DeclVal<T>()); }) (R&& Base, T&& Predicate)
|
||||
using FClosure = decltype([]<CViewableRange R, typename T> requires (requires { Ranges::Filter(DeclVal<R>(), DeclVal<T>()); }) (R&& Base, T&& Predicate)
|
||||
{
|
||||
return Range::Filter(Forward<R>(Base), Forward<T>(Predicate));
|
||||
return Ranges::Filter(Forward<R>(Base), Forward<T>(Predicate));
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, TDecay<Pred>>(Forward<Pred>(Predicate));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
@ -3,19 +3,19 @@
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/MoveIterator.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Range/Pipe.h"
|
||||
#include "Range/View.h"
|
||||
#include "Range/AllView.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/MoveIterator.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/AllView.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/**
|
||||
* A view adapter which dereferences to a rvalue reference.
|
||||
@ -34,30 +34,36 @@ public:
|
||||
|
||||
FORCEINLINE constexpr explicit TMoveView(V InBase) : Base(MoveTemp(InBase)) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() { return MakeMoveIterator(Range::Begin(Base)); }
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() requires (!CSimpleView<V>)
|
||||
{
|
||||
return MakeMoveIterator(Ranges::Begin(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End()
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const V>)
|
||||
{
|
||||
return MakeMoveIterator(Ranges::Begin(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() requires (!CSimpleView<V>)
|
||||
{
|
||||
if constexpr (CCommonRange<V>)
|
||||
{
|
||||
return MakeMoveIterator(Range::End(Base));
|
||||
return MakeMoveIterator(Ranges::End(Base));
|
||||
}
|
||||
else return MakeMoveSentinel(Range::End(Base));
|
||||
else return MakeMoveSentinel(Ranges::End(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const V>) { return MakeMoveIterator(Range::Begin(Base)); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V>)
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V>)
|
||||
{
|
||||
if constexpr (CCommonRange<V>)
|
||||
{
|
||||
return MakeMoveIterator(Range::End(Base));
|
||||
return MakeMoveIterator(Ranges::End(Base));
|
||||
}
|
||||
else return MakeMoveSentinel(Range::End(Base));
|
||||
else return MakeMoveSentinel(Ranges::End(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< V>) { return Range::Num(Base); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<const V>) { return Range::Num(Base); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< V>) { return Ranges::Num(Base); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<const V>) { return Ranges::Num(Base); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible<V>) { return Base; }
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() && { return MoveTemp(Base); }
|
||||
@ -80,12 +86,12 @@ static_assert( CRandomAccessRange<TMoveView<TAllView<IRange< IContiguousIterat
|
||||
static_assert(CCommonRange<TMoveView<TAllView<ICommonRange<IForwardIterator<int>>>>>);
|
||||
static_assert( CView<TMoveView<TAllView< IRange< IInputIterator<int>>>>>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
template <typename T>
|
||||
constexpr bool bEnableBorrowedRange<Range::TMoveView<T>> = bEnableBorrowedRange<T>;
|
||||
constexpr bool bEnableBorrowedRange<Ranges::TMoveView<T>> = bEnableBorrowedRange<T>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** Creates A view adapter that dereferences to a rvalue reference. */
|
||||
template <CViewableRange R> requires (requires { TMoveView(DeclVal<R>()); })
|
||||
@ -97,15 +103,15 @@ NODISCARD FORCEINLINE constexpr auto Move(R&& Base)
|
||||
/** Creates A view adapter that dereferences to a rvalue reference. */
|
||||
NODISCARD FORCEINLINE constexpr auto Move()
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R> requires (requires { Range::Move(DeclVal<R>()); }) (R&& Base)
|
||||
using FClosure = decltype([]<CViewableRange R> requires (requires { Ranges::Move(DeclVal<R>()); }) (R&& Base)
|
||||
{
|
||||
return Range::Move(Forward<R>(Base));
|
||||
return Ranges::Move(Forward<R>(Base));
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure>();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Templates/Tuple.h"
|
||||
#include "Templates/Invoke.h"
|
||||
#include "Templates/Utility.h"
|
||||
@ -11,7 +11,7 @@ NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/**
|
||||
* An interface class template for defining a range adaptor closure.
|
||||
@ -139,7 +139,7 @@ NODISCARD FORCEINLINE constexpr auto operator|(T&& LHS, U&& RHS)
|
||||
return TPipeClosure<TRemoveCVRef<T>, TRemoveCVRef<U>>(Forward<T>(LHS), Forward<U>(RHS));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
14
Redcraft.Utility/Source/Public/Ranges/Ranges.h
Normal file
14
Redcraft.Utility/Source/Public/Ranges/Ranges.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/Conversion.h"
|
||||
#include "Ranges/Factory.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/AllView.h"
|
||||
#include "Ranges/MoveView.h"
|
||||
#include "Ranges/FilterView.h"
|
||||
#include "Ranges/TransformView.h"
|
||||
#include "Ranges/TakeView.h"
|
||||
#include "Ranges/TakeWhileView.h"
|
@ -3,20 +3,20 @@
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/CountedIterator.h"
|
||||
#include "Numeric/Math.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Range/Pipe.h"
|
||||
#include "Range/View.h"
|
||||
#include "Range/AllView.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/CountedIterator.h"
|
||||
#include "Numerics/Math.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/AllView.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/**
|
||||
* A view adapter that includes a specified number of elements from the beginning of a range.
|
||||
@ -36,17 +36,17 @@ public:
|
||||
|
||||
FORCEINLINE constexpr TTakeView(V InBase, size_t InCount) : Base(MoveTemp(InBase)), Count(InCount) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin()
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() requires (!CSimpleView<V>)
|
||||
{
|
||||
if constexpr (CSizedRange<V>)
|
||||
{
|
||||
if constexpr (CRandomAccessRange<V>)
|
||||
{
|
||||
return Range::Begin(Base);
|
||||
return Ranges::Begin(Base);
|
||||
}
|
||||
else return MakeCountedIterator(Range::Begin(Base), Num());
|
||||
else return MakeCountedIterator(Ranges::Begin(Base), Num());
|
||||
}
|
||||
else return MakeCountedIterator(Range::Begin(Base), Count);
|
||||
else return MakeCountedIterator(Ranges::Begin(Base), Count);
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const V>)
|
||||
@ -55,24 +55,24 @@ public:
|
||||
{
|
||||
if constexpr (CRandomAccessRange<const V>)
|
||||
{
|
||||
return Range::Begin(Base);
|
||||
return Ranges::Begin(Base);
|
||||
}
|
||||
else return MakeCountedIterator(Range::Begin(Base), Num());
|
||||
else return MakeCountedIterator(Ranges::Begin(Base), Num());
|
||||
}
|
||||
else return MakeCountedIterator(Range::Begin(Base), Count);
|
||||
else return MakeCountedIterator(Ranges::Begin(Base), Count);
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End()
|
||||
NODISCARD FORCEINLINE constexpr auto End() requires (!CSimpleView<V>)
|
||||
{
|
||||
if constexpr (CSizedRange<V>)
|
||||
{
|
||||
if constexpr (CRandomAccessRange<V>)
|
||||
{
|
||||
return Range::Begin(Base) + Num();
|
||||
return Ranges::Begin(Base) + Num();
|
||||
}
|
||||
else return DefaultSentinel;
|
||||
}
|
||||
else return FSentinelImpl<false>(Range::End(Base));
|
||||
else return FSentinelImpl<false>(Ranges::End(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V>)
|
||||
@ -81,15 +81,15 @@ public:
|
||||
{
|
||||
if constexpr (CRandomAccessRange<const V>)
|
||||
{
|
||||
return Range::Begin(Base) + Num();
|
||||
return Ranges::Begin(Base) + Num();
|
||||
}
|
||||
else return DefaultSentinel;
|
||||
}
|
||||
else return FSentinelImpl<true>(Range::End(Base));
|
||||
else return FSentinelImpl<true>(Ranges::End(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< V>) { return Math::Min(Range::Num(Base), Count); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<const V>) { return Math::Min(Range::Num(Base), Count); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< V>) { return Math::Min(Ranges::Num(Base), Count); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<const V>) { return Math::Min(Ranges::Num(Base), Count); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible<V>) { return Base; }
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() && { return MoveTemp(Base); }
|
||||
@ -154,12 +154,12 @@ static_assert( CView<TTakeView<TAllView< IRange<IInputOrOutputIterator
|
||||
|
||||
static_assert(COutputRange<TTakeView<TAllView<IRange<IOutputIterator<int&>>>>, int>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
template <typename T>
|
||||
constexpr bool bEnableBorrowedRange<Range::TTakeView<T>> = bEnableBorrowedRange<T>;
|
||||
constexpr bool bEnableBorrowedRange<Ranges::TTakeView<T>> = bEnableBorrowedRange<T>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** Creates A view adapter that includes a specified number of elements from the beginning of a range. */
|
||||
template <CViewableRange R> requires (requires { TTakeView(DeclVal<R>(), DeclVal<size_t>()); })
|
||||
@ -171,15 +171,15 @@ NODISCARD FORCEINLINE constexpr auto Take(R&& Base, size_t Count)
|
||||
/** Creates A view adapter that includes a specified number of elements from the beginning of a range. */
|
||||
NODISCARD FORCEINLINE constexpr auto Take(size_t Count)
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R> requires (requires { Range::Take(DeclVal<R>(), DeclVal<size_t>()); }) (R&& Base, size_t Count)
|
||||
using FClosure = decltype([]<CViewableRange R> requires (requires { Ranges::Take(DeclVal<R>(), DeclVal<size_t>()); }) (R&& Base, size_t Count)
|
||||
{
|
||||
return Range::Take(Forward<R>(Base), Count);
|
||||
return Ranges::Take(Forward<R>(Base), Count);
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, size_t>(Count);
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
149
Redcraft.Utility/Source/Public/Ranges/TakeWhileView.h
Normal file
149
Redcraft.Utility/Source/Public/Ranges/TakeWhileView.h
Normal file
@ -0,0 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/CountedIterator.h"
|
||||
#include "Numerics/Math.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/AllView.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/**
|
||||
* A view adapter that includes elements that satisfy the predicate from the beginning of the range.
|
||||
* When based on an input view, the take while view satisfies at least an input view up to a contiguous view.
|
||||
* When based on a forward and output view, the take while view satisfies an output view.
|
||||
*/
|
||||
template <CInputRange V, CPredicate<TRangeReference<V>> Pred> requires (CView<V> && CObject<Pred> && CMoveConstructible<Pred>)
|
||||
class TTakeWhileView : public IBasicViewInterface<TTakeWhileView<V, Pred>>
|
||||
{
|
||||
private:
|
||||
|
||||
template <bool bConst> class FSentinelImpl;
|
||||
|
||||
public:
|
||||
|
||||
using FElementType = TRangeElement<V>;
|
||||
using FReference = TRangeReference<V>;
|
||||
|
||||
FORCEINLINE constexpr TTakeWhileView() requires (CDefaultConstructible<V>&& CDefaultConstructible<Pred>) = default;
|
||||
|
||||
FORCEINLINE constexpr explicit TTakeWhileView(V InBase, Pred InPredicate) : Base(MoveTemp(InBase)), Predicate(MoveTemp(InPredicate)) { }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() requires (!CSimpleView<V>)
|
||||
{
|
||||
return Ranges::Begin(Base);
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const V> && CPredicate<const Pred&, TRangeReference<const V>>)
|
||||
{
|
||||
return Ranges::Begin(Base);
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() requires (!CSimpleView<V>)
|
||||
{
|
||||
return FSentinelImpl<false>(Ranges::End(Base), AddressOf(Predicate));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V> && CPredicate<const Pred&, TRangeReference<const V>>)
|
||||
{
|
||||
return FSentinelImpl<true>(Ranges::End(Base), AddressOf(Predicate));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible<V>) { return Base; }
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() && { return MoveTemp(Base); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr const Pred& GetPredicate() const { return Predicate; }
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS V Base;
|
||||
|
||||
NO_UNIQUE_ADDRESS Pred Predicate;
|
||||
|
||||
template <bool bConst>
|
||||
class FSentinelImpl final
|
||||
{
|
||||
private:
|
||||
|
||||
using FBase = TConditional<bConst, const V, V>;
|
||||
using FPred = TConditional<bConst, const Pred, Pred>;
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl() = default;
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl(FSentinelImpl<!bConst> Sentinel) requires (bConst && CConvertibleTo<TRangeSentinel<V>, TRangeSentinel<FBase>>)
|
||||
: Current(Sentinel.Current), Predicate(Sentinel.Predicate)
|
||||
{ }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr bool operator==(const TRangeIterator<FBase>& InValue) const&
|
||||
{
|
||||
return InValue == Current || !InvokeResult<bool>(*Predicate, *InValue);
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TRangeSentinel<FBase> GetBase() const { return Current; }
|
||||
|
||||
private:
|
||||
|
||||
NO_UNIQUE_ADDRESS TRangeSentinel<FBase> Current;
|
||||
|
||||
FPred* Predicate;
|
||||
|
||||
FORCEINLINE constexpr FSentinelImpl(TRangeSentinel<FBase> InCurrent, FPred* InPredicate) : Current(InCurrent), Predicate(InPredicate) { }
|
||||
|
||||
friend TTakeWhileView;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename Pred>
|
||||
TTakeWhileView(R&&, Pred) -> TTakeWhileView<TAllView<R>, Pred>;
|
||||
|
||||
static_assert( CInputRange<TTakeWhileView<TAllView<IRange< IInputIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert( CForwardRange<TTakeWhileView<TAllView<IRange< IForwardIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert(CBidirectionalRange<TTakeWhileView<TAllView<IRange<IBidirectionalIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert( CRandomAccessRange<TTakeWhileView<TAllView<IRange< IRandomAccessIterator<int&>>>, bool(*)(int)>>);
|
||||
static_assert( CContiguousRange<TTakeWhileView<TAllView<IRange< IContiguousIterator<int&>>>, bool(*)(int)>>);
|
||||
|
||||
static_assert(CView<TTakeWhileView<TAllView<IRange<IInputIterator<int>>>, bool(*)(int)>>);
|
||||
|
||||
static_assert(COutputRange<TTakeWhileView<TAllView<IRange<IForwardIterator<int&>>>, bool(*)(int)>, int>);
|
||||
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** Creates A view adapter that includes elements that satisfy the predicate from the beginning of the range. */
|
||||
template <CViewableRange R, typename Pred> requires (requires { TTakeWhileView(DeclVal<R>(), DeclVal<Pred>()); })
|
||||
NODISCARD FORCEINLINE constexpr auto TakeWhile(R&& Base, Pred&& Predicate)
|
||||
{
|
||||
return TTakeWhileView(Forward<R>(Base), Forward<Pred>(Predicate));
|
||||
}
|
||||
|
||||
/** Creates A view adapter that includes elements that satisfy the predicate from the beginning of the range. */
|
||||
template <typename Pred>
|
||||
NODISCARD FORCEINLINE constexpr auto TakeWhile(Pred&& Predicate)
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R, typename T> requires (requires { Ranges::TakeWhile(DeclVal<R>(), DeclVal<T>()); }) (R&& Base, T&& Predicate)
|
||||
{
|
||||
return Ranges::TakeWhile(Forward<R>(Base), Forward<T>(Predicate));
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, TDecay<Pred>>(Forward<Pred>(Predicate));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Range/View.h"
|
||||
#include "Range/Pipe.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Range/AllView.h"
|
||||
#include "Ranges/View.h"
|
||||
#include "Ranges/Pipe.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/AllView.h"
|
||||
#include "Templates/Invoke.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
@ -13,7 +13,7 @@ NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/**
|
||||
* A view adapter of a sequence that applies a transformation function to each element.
|
||||
@ -39,36 +39,36 @@ public:
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin()
|
||||
{
|
||||
return FIteratorImpl<false>(*this, Range::Begin(Base));
|
||||
return FIteratorImpl<false>(*this, Ranges::Begin(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const V> && CRegularInvocable<const F&, TRangeReference<const V>>)
|
||||
{
|
||||
return FIteratorImpl<true>(*this, Range::Begin(Base));
|
||||
return FIteratorImpl<true>(*this, Ranges::Begin(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End()
|
||||
{
|
||||
if constexpr (CCommonRange<V>)
|
||||
{
|
||||
return FIteratorImpl<false>(*this, Range::End(Base));
|
||||
return FIteratorImpl<false>(*this, Ranges::End(Base));
|
||||
}
|
||||
|
||||
else return FSentinelImpl<false>(*this, Range::End(Base));
|
||||
else return FSentinelImpl<false>(*this, Ranges::End(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V> && CRegularInvocable<const F&, TRangeReference<const V>>)
|
||||
{
|
||||
if constexpr (CCommonRange<const V>)
|
||||
{
|
||||
return FIteratorImpl<true>(*this, Range::End(Base));
|
||||
return FIteratorImpl<true>(*this, Ranges::End(Base));
|
||||
}
|
||||
|
||||
else return FSentinelImpl<true>(*this, Range::End(Base));
|
||||
else return FSentinelImpl<true>(*this, Ranges::End(Base));
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< V>) { return Range::Num(Base); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<const V>) { return Range::Num(Base); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CSizedRange< V>) { return Ranges::Num(Base); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedRange<const V>) { return Ranges::Num(Base); }
|
||||
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() const& requires (CCopyConstructible<V>) { return Base; }
|
||||
NODISCARD FORCEINLINE constexpr V GetBase() && { return MoveTemp(Base); }
|
||||
@ -175,7 +175,7 @@ private:
|
||||
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FSentinelImpl& LHS, const FIteratorImpl<bConst>& RHS)
|
||||
requires CSizedSentinelFor<TRangeSentinel<FBase>, TRangeIterator<FBase>>
|
||||
{
|
||||
return RHS.GetBase() - LHS.GetBase();
|
||||
return LHS.GetBase() - RHS.GetBase();
|
||||
}
|
||||
|
||||
NODISCARD FORCEINLINE constexpr TRangeSentinel<FBase> GetBase() const { return Current; }
|
||||
@ -206,9 +206,9 @@ static_assert( CView<TTransformView<TAllView< IRange< IInputIterator
|
||||
|
||||
static_assert(COutputRange<TTransformView<TAllView<IRange<IForwardIterator<int>>>, int&(*)(int)>, int>);
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** Creates A view adapter of a sequence that applies a transformation function to each element. */
|
||||
template <CViewableRange R, typename F> requires (requires { TTransformView(DeclVal<R>(), DeclVal<F>()); })
|
||||
@ -221,15 +221,15 @@ NODISCARD FORCEINLINE constexpr auto Transform(R&& Base, F&& Func)
|
||||
template <typename F>
|
||||
NODISCARD FORCEINLINE constexpr auto Transform(F&& Func)
|
||||
{
|
||||
using FClosure = decltype([]<CViewableRange R, typename T> requires (requires { Range::Transform(DeclVal<R>(), DeclVal<T>()); }) (R&& Base, T&& Func)
|
||||
using FClosure = decltype([]<CViewableRange R, typename T> requires (requires { Ranges::Transform(DeclVal<R>(), DeclVal<T>()); }) (R&& Base, T&& Func)
|
||||
{
|
||||
return Range::Transform(Forward<R>(Base), Forward<T>(Func));
|
||||
return Ranges::Transform(Forward<R>(Base), Forward<T>(Func));
|
||||
});
|
||||
|
||||
return TAdaptorClosure<FClosure, TDecay<F>>(Forward<F>(Func));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
@ -3,10 +3,10 @@
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/ReverseIterator.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
@ -20,7 +20,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
|
||||
template <typename R>
|
||||
inline constexpr bool bEnableBorrowedRange = false;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** @return The iterator to the beginning of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
@ -45,12 +45,12 @@ NODISCARD FORCEINLINE constexpr const T* Begin(initializer_list<T>& Container)
|
||||
return Container.begin();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
template <typename R>
|
||||
using TRangeIterator = decltype(Range::Begin(DeclVal<R&>()));
|
||||
using TRangeIterator = decltype(Ranges::Begin(DeclVal<R&>()));
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** @return The iterator to the end of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
@ -75,13 +75,13 @@ NODISCARD FORCEINLINE constexpr const T* End(initializer_list<T>& Container)
|
||||
return Container.end();
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
template <typename R>
|
||||
using TRangeSentinel = decltype(Range::End(DeclVal<R&>()));
|
||||
using TRangeSentinel = decltype(Ranges::End(DeclVal<R&>()));
|
||||
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** @return The reverse iterator to the beginning of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
@ -97,12 +97,12 @@ template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRe
|
||||
&& (CSameAs<TRangeIterator<T>, TRangeSentinel<T>> && CBidirectionalIterator<TRangeIterator<T>>))
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container)
|
||||
{
|
||||
return MakeReverseIterator(Range::End(Forward<T>(Container)));
|
||||
return MakeReverseIterator(Ranges::End(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
/** @return The reverse iterator to the end of a container. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& requires(T&& Container) { { Container.REnd() } -> CSentinelFor<decltype(Range::RBegin(DeclVal<T&>()))>; })
|
||||
&& requires(T&& Container) { { Container.REnd() } -> CSentinelFor<decltype(Ranges::RBegin(DeclVal<T&>()))>; })
|
||||
NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
|
||||
{
|
||||
return Container.REnd();
|
||||
@ -110,14 +110,14 @@ NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
|
||||
|
||||
/** Overloads the REnd algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.REnd() } -> CSentinelFor<decltype(Range::RBegin(DeclVal<T&>()))>; }
|
||||
&& !requires(T&& Container) { { Container.REnd() } -> CSentinelFor<decltype(Ranges::RBegin(DeclVal<T&>()))>; }
|
||||
&& (CSameAs<TRangeIterator<T>, TRangeSentinel<T>> && CBidirectionalIterator<TRangeIterator<T>>))
|
||||
NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
|
||||
{
|
||||
return MakeReverseIterator(Range::Begin(Forward<T>(Container)));
|
||||
return MakeReverseIterator(Ranges::Begin(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
template <typename R>
|
||||
using TRangeElement = TIteratorElement<TRangeIterator<R>>;
|
||||
@ -131,7 +131,7 @@ using TRangeReference = TIteratorReference<TRangeIterator<R>>;
|
||||
template <typename R>
|
||||
using TRangeRValueReference = TIteratorRValueReference<TRangeIterator<R>>;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** @return The pointer to the container element storage. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
@ -144,19 +144,19 @@ NODISCARD FORCEINLINE constexpr auto GetData(T&& Container)
|
||||
/** Overloads the GetData algorithm for synthesized. */
|
||||
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
|
||||
&& !requires(T&& Container) { { Container.GetData() } -> CSameAs<TAddPointer<TRangeReference<T>>>; }
|
||||
&& requires(T&& Container) { { Range::Begin(Forward<T>(Container)) } -> CContiguousIterator; })
|
||||
&& requires(T&& Container) { { Ranges::Begin(Forward<T>(Container)) } -> CContiguousIterator; })
|
||||
NODISCARD FORCEINLINE constexpr auto GetData(T&& Container)
|
||||
{
|
||||
return ToAddress(Range::Begin(Forward<T>(Container)));
|
||||
return ToAddress(Ranges::Begin(Forward<T>(Container)));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
/** Disable the CSizedRange concept for specific types. */
|
||||
template <typename R>
|
||||
inline constexpr bool bDisableSizedRange = false;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** @return The number of elements in the container. */
|
||||
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
@ -180,7 +180,7 @@ template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
|
||||
&& CSizedSentinelFor<TRangeSentinel<T>, TRangeIterator<T>> && CForwardIterator<TRangeIterator<T>>)
|
||||
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container)
|
||||
{
|
||||
return Range::End(Forward<T>(Container)) - Range::Begin(Forward<T>(Container));
|
||||
return Ranges::End(Forward<T>(Container)) - Ranges::Begin(Forward<T>(Container));
|
||||
}
|
||||
|
||||
/** Overloads the Num algorithm for initializer_list. */
|
||||
@ -203,7 +203,7 @@ template <typename T> requires ((CBoundedArray<TRemoveReference<T>>
|
||||
&& !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; })
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Range::Num(Forward<T>(Container)) == 0;
|
||||
return Ranges::Num(Forward<T>(Container)) == 0;
|
||||
}
|
||||
|
||||
/** Overloads the IsEmpty algorithm for synthesized. */
|
||||
@ -213,16 +213,17 @@ template <typename T> requires (!CBoundedArray<TRemoveReference<T>>
|
||||
&& CForwardIterator<TRangeIterator<T>>)
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container)
|
||||
{
|
||||
return Range::End(Forward<T>(Container)) == Range::Begin(Forward<T>(Container));
|
||||
return Ranges::End(Forward<T>(Container)) == Ranges::Begin(Forward<T>(Container));
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a range.
|
||||
* A range is an iterator-sentinel pair that represents a sequence of elements.
|
||||
* This concept does not require that iterator-sentinel pair can be fetched multiple times
|
||||
* from the range object. again this means that const R may not be a range if R is a range,
|
||||
* if the range does not satisfy the forward range, otherwise it is equality-preserving.
|
||||
* Again, this means that const R may not be a range if R is a range,
|
||||
* e.g. fetching the iterator-sentinel pair from the input range may require moving the iterator
|
||||
* directly from the range object and thus the range object may be modified.
|
||||
*/
|
||||
@ -261,16 +262,15 @@ concept CBorrowedRange = CRange<R> && (CLValueReference<R> || bEnableBorrowedRan
|
||||
|
||||
/**
|
||||
* A concept specifies a type is a sized range.
|
||||
* Indicates the expression 'Range::Num(Range)' can get the size of the range at constant time
|
||||
* without modifying the range object. Modifying the range usually occurs when the iterator of
|
||||
* the range is an input iterator. Indirect calculation of the range by obtaining the iterator
|
||||
* may cause the range to become invalid, that is, the iterator cannot be obtained again.
|
||||
* Indicates the expression 'Ranges::Num(Range)' can get the size of the range at constant time
|
||||
* without modifying the range object. A sized range may support fetched size before fetched iterator-sentinel pair
|
||||
* if the range does not satisfy the forward range, otherwise it is equality-preserving.
|
||||
*/
|
||||
template <typename R>
|
||||
concept CSizedRange = CRange<R>
|
||||
&& requires(R Range)
|
||||
{
|
||||
{ Range::Num(Range) } -> CConvertibleTo<size_t>;
|
||||
{ Ranges::Num(Range) } -> CConvertibleTo<size_t>;
|
||||
};
|
||||
|
||||
/** This is an example of a sized range type, indicate the traits that define a sized range type. */
|
||||
@ -337,7 +337,7 @@ template <typename R>
|
||||
concept CContiguousRange = CRandomAccessRange<R> && CContiguousIterator<TRangeIterator<R>>
|
||||
&& requires(R& Range)
|
||||
{
|
||||
{ Range::GetData(Range) } -> CSameAs<TAddPointer<TRangeReference<R>>>;
|
||||
{ Ranges::GetData(Range) } -> CSameAs<TAddPointer<TRangeReference<R>>>;
|
||||
};
|
||||
|
||||
/** This is an example of a contiguous range type, indicate the traits that define a contiguous range type. */
|
||||
@ -354,7 +354,7 @@ struct IContiguousRange /* : IRange<I, S> */
|
||||
/**
|
||||
* Get the pointer to the container element storage.
|
||||
* The function is optional if the range size can be computed indirectly from the iterator.
|
||||
* If the function is provided, then the expression 'ToAddress(Range::Begin(Range)) == Range::GetData(Range)'
|
||||
* If the function is provided, then the expression 'ToAddress(Ranges::Begin(Range)) == Ranges::GetData(Range)'
|
||||
* must be satisfied to always be true.
|
||||
* If the function is const, it means that the const IContiguousRange satisfies CContiguousRange.
|
||||
*/
|
@ -3,18 +3,18 @@
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/ReverseIterator.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/ReverseIterator.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Ranges/Utility.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** An interface class template for defining a view. Not directly instantiable. */
|
||||
template <CClass T> requires (CSameAs<T, TRemoveCV<T>>)
|
||||
@ -23,43 +23,43 @@ class IBasicViewInterface
|
||||
public:
|
||||
|
||||
/** @return The pointer to the underlying element storage. */
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() requires (CContiguousIterator<TRangeIterator< T>>) { return ToAddress(Range::Begin(static_cast< T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousIterator<TRangeIterator<const T>>) { return ToAddress(Range::Begin(static_cast<const T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() requires (CContiguousIterator<TRangeIterator< T>>) { return ToAddress(Ranges::Begin(static_cast< T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto GetData() const requires (CContiguousIterator<TRangeIterator<const T>>) { return ToAddress(Ranges::Begin(static_cast<const T&>(*this))); }
|
||||
|
||||
/** @return The reverse iterator to the first or end element. */
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin() requires (CBidirectionalRange< T> && CCommonRange< T>) { return MakeReverseIterator(Range::End (static_cast< T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto REnd() requires (CBidirectionalRange< T> && CCommonRange< T>) { return MakeReverseIterator(Range::Begin(static_cast< T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin() const requires (CBidirectionalRange<const T> && CCommonRange<const T>) { return MakeReverseIterator(Range::End (static_cast<const T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto REnd() const requires (CBidirectionalRange<const T> && CCommonRange<const T>) { return MakeReverseIterator(Range::Begin(static_cast<const T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin() requires (CBidirectionalRange< T> && CCommonRange< T>) { return MakeReverseIterator(Ranges::End (static_cast< T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto REnd() requires (CBidirectionalRange< T> && CCommonRange< T>) { return MakeReverseIterator(Ranges::Begin(static_cast< T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto RBegin() const requires (CBidirectionalRange<const T> && CCommonRange<const T>) { return MakeReverseIterator(Ranges::End (static_cast<const T&>(*this))); }
|
||||
NODISCARD FORCEINLINE constexpr auto REnd() const requires (CBidirectionalRange<const T> && CCommonRange<const T>) { return MakeReverseIterator(Ranges::Begin(static_cast<const T&>(*this))); }
|
||||
|
||||
/** @return The number of elements in the container. */
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CForwardRange< T> && CSizedSentinelFor<TRangeSentinel< T>, TRangeIterator< T>>) { T& Derived = static_cast< T&>(*this); return Range::End(Derived) - Range::Begin(Derived); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CForwardRange<const T> && CSizedSentinelFor<TRangeSentinel<const T>, TRangeIterator<const T>>) { const T& Derived = static_cast<const T&>(*this); return Range::End(Derived) - Range::Begin(Derived); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() requires (CForwardRange< T> && CSizedSentinelFor<TRangeSentinel< T>, TRangeIterator< T>>) { T& Derived = static_cast< T&>(*this); return Ranges::End(Derived) - Ranges::Begin(Derived); }
|
||||
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CForwardRange<const T> && CSizedSentinelFor<TRangeSentinel<const T>, TRangeIterator<const T>>) { const T& Derived = static_cast<const T&>(*this); return Ranges::End(Derived) - Ranges::Begin(Derived); }
|
||||
|
||||
/** @return true if the container is empty, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() requires (CSizedRange< T> || CForwardRange< T>) { T& Derived = static_cast< T&>(*this); if constexpr (CSizedRange< T>) return Range::Num(Derived) == 0; else return Range::Begin(Derived) == Range::End(Derived); }
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (CSizedRange<const T> || CForwardRange<const T>) { const T& Derived = static_cast<const T&>(*this); if constexpr (CSizedRange<const T>) return Range::Num(Derived) == 0; else return Range::Begin(Derived) == Range::End(Derived); }
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() requires (CSizedRange< T> || CForwardRange< T>) { T& Derived = static_cast< T&>(*this); if constexpr (CSizedRange< T>) return Ranges::Num(Derived) == 0; else return Ranges::Begin(Derived) == Ranges::End(Derived); }
|
||||
NODISCARD FORCEINLINE constexpr bool IsEmpty() const requires (CSizedRange<const T> || CForwardRange<const T>) { const T& Derived = static_cast<const T&>(*this); if constexpr (CSizedRange<const T>) return Ranges::Num(Derived) == 0; else return Ranges::Begin(Derived) == Ranges::End(Derived); }
|
||||
|
||||
/** @return true if the container is empty, false otherwise. */
|
||||
NODISCARD FORCEINLINE constexpr explicit operator bool() requires (requires { Range::IsEmpty(DeclVal< T&>()); }) { return !Range::IsEmpty(static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr explicit operator bool() const requires (requires { Range::IsEmpty(DeclVal<const T&>()); }) { return !Range::IsEmpty(static_cast<const T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr explicit operator bool() requires (requires { Ranges::IsEmpty(DeclVal< T&>()); }) { return !Ranges::IsEmpty(static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr explicit operator bool() const requires (requires { Ranges::IsEmpty(DeclVal<const T&>()); }) { return !Ranges::IsEmpty(static_cast<const T&>(*this)); }
|
||||
|
||||
/** @return The reference to the requested element. */
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) operator[](size_t Index) requires (CRandomAccessRange< T>) { return Range::Begin(static_cast< T&>(*this))[Index]; }
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) operator[](size_t Index) const requires (CRandomAccessRange<const T>) { return Range::Begin(static_cast<const T&>(*this))[Index]; }
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) operator[](size_t Index) requires (CRandomAccessRange< T>) { return Ranges::Begin(static_cast< T&>(*this))[Index]; }
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) operator[](size_t Index) const requires (CRandomAccessRange<const T>) { return Ranges::Begin(static_cast<const T&>(*this))[Index]; }
|
||||
|
||||
/** @return The reference to the first or last element. */
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) Front() requires (CForwardRange< T>) { return *Range::Begin(static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) Front() const requires (CForwardRange<const T>) { return *Range::Begin(static_cast<const T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) Back() requires (CBidirectionalRange< T> && CCommonRange< T>) { return *Range::RBegin(static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) Back() const requires (CBidirectionalRange<const T> && CCommonRange<const T>) { return *Range::RBegin(static_cast<const T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) Front() requires (CForwardRange< T>) { return *Ranges::Begin(static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) Front() const requires (CForwardRange<const T>) { return *Ranges::Begin(static_cast<const T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) Back() requires (CBidirectionalRange< T> && CCommonRange< T>) { return *Ranges::RBegin(static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr decltype(auto) Back() const requires (CBidirectionalRange<const T> && CCommonRange<const T>) { return *Ranges::RBegin(static_cast<const T&>(*this)); }
|
||||
|
||||
// ~Begin ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT.
|
||||
|
||||
NODISCARD FORCEINLINE constexpr auto begin() requires (CRange< T>) { return Range::Begin(static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr auto end() requires (CRange< T>) { return Range::End (static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr auto begin() const requires (CRange<const T>) { return Range::Begin(static_cast<const T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr auto end() const requires (CRange<const T>) { return Range::End (static_cast<const T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr auto begin() requires (CRange< T>) { return Ranges::Begin(static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr auto end() requires (CRange< T>) { return Ranges::End (static_cast< T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr auto begin() const requires (CRange<const T>) { return Ranges::Begin(static_cast<const T&>(*this)); }
|
||||
NODISCARD FORCEINLINE constexpr auto end() const requires (CRange<const T>) { return Ranges::End (static_cast<const T&>(*this)); }
|
||||
|
||||
// ~End ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT.
|
||||
|
||||
@ -75,14 +75,14 @@ private:
|
||||
friend T;
|
||||
};
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
/**
|
||||
* A concept specifies that a range is a view, that is, it has constant time copy, move and assignment.
|
||||
* Specify, a view can be movable only but not copyable, or it can be both movable and copyable.
|
||||
*/
|
||||
template <typename V>
|
||||
concept CView = CRange<V> && CMovable<V> && CDerivedFrom<V, Range::IBasicViewInterface<TRemoveCVRef<V>>>;
|
||||
concept CView = CRange<V> && CMovable<V> && CDerivedFrom<V, Ranges::IBasicViewInterface<TRemoveCVRef<V>>>;
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
@ -91,14 +91,20 @@ template <typename T> struct TIsInitializerList<initializer_list<T>> : FTrue {
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
/** A concept specifies that a viewable range that can be converted into a view through Range::All. */
|
||||
/** A concept specifies that a viewable range that can be converted into a view through Ranges::All. */
|
||||
template <typename R>
|
||||
concept CViewableRange = CRange<R>
|
||||
&& ((CView<TRemoveCVRef<R>> && CConstructibleFrom<TRemoveCVRef<R>, R>)
|
||||
|| (!CView<TRemoveCVRef<R>> && (CLValueReference<R> || (CMovable<TRemoveReference<R>>
|
||||
&& !NAMESPACE_PRIVATE::TIsInitializerList<TRemoveCVRef<R>>::Value))));
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
/** A concept specifies that a view uses the same iterator and sentinel type for both const and non-const views. */
|
||||
template <typename V>
|
||||
concept CSimpleView = CView<V> && CRange<const V>
|
||||
&& CSameAs<TRangeIterator<V>, TRangeIterator<const V>>
|
||||
&& CSameAs<TRangeSentinel<V>, TRangeSentinel<const V>>;
|
||||
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** A simple view that combines an iterator-sentinel pair into a view. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S = I>
|
||||
@ -106,8 +112,6 @@ class TRangeView : public IBasicViewInterface<TRangeView<I, S>>
|
||||
{
|
||||
public:
|
||||
|
||||
using FElementType = TIteratorElement<I>;
|
||||
|
||||
FORCEINLINE constexpr TRangeView() requires (CDefaultConstructible<I>) = default;
|
||||
|
||||
FORCEINLINE constexpr TRangeView(I InFirst, S InLast) : First(MoveTemp(InFirst)), Last(InLast) { }
|
||||
@ -131,12 +135,12 @@ private:
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S>
|
||||
TRangeView(I, S) -> TRangeView<I, S>;
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
template <typename I, typename S>
|
||||
constexpr bool bEnableBorrowedRange<Range::TRangeView<I, S>> = true;
|
||||
constexpr bool bEnableBorrowedRange<Ranges::TRangeView<I, S>> = true;
|
||||
|
||||
NAMESPACE_BEGIN(Range)
|
||||
NAMESPACE_BEGIN(Ranges)
|
||||
|
||||
/** Creates A simple view that combines an iterator-sentinel pair. */
|
||||
template <CInputOrOutputIterator I, CSentinelFor<I> S = I>
|
||||
@ -145,7 +149,7 @@ NODISCARD FORCEINLINE constexpr TRangeView<I, S> View(I First, S Last)
|
||||
return TRangeView<I, S>(MoveTemp(First), Last);
|
||||
}
|
||||
|
||||
NAMESPACE_END(Range)
|
||||
NAMESPACE_END(Ranges)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
File diff suppressed because it is too large
Load Diff
@ -1,698 +0,0 @@
|
||||
#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 "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "String/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
|
@ -57,7 +57,7 @@ struct TLiteral<u32char>
|
||||
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<CharType>::Select(TEXT(StringLiteral), WTEXT(StringLiteral), U8TEXT(StringLiteral), U16TEXT(StringLiteral), U32TEXT(StringLiteral))
|
||||
#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");
|
||||
@ -85,7 +85,14 @@ struct TChar
|
||||
|
||||
NODISCARD FORCEINLINE static constexpr bool IsValid(FCharType InChar)
|
||||
{
|
||||
if constexpr (CSameAs<FCharType, u8char>)
|
||||
if constexpr (TChar::IsASCII() && CSameAs<FCharType, char>)
|
||||
{
|
||||
if (0x00 <= InChar && InChar <= 0x7F) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
else if constexpr (CSameAs<FCharType, u8char>)
|
||||
{
|
||||
if ((InChar & 0b10000000) == 0b00000000) return true;
|
||||
|
||||
@ -103,13 +110,13 @@ struct TChar
|
||||
// Windows uses UTF-16 encoding for wchar.
|
||||
else if constexpr (PLATFORM_WINDOWS && (CSameAs<FCharType, wchar>))
|
||||
{
|
||||
return TChar::IsValid(static_cast<u16char>(InChar));
|
||||
return TChar<u16char>::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));
|
||||
return TChar<u32char>::IsValid(static_cast<u32char>(InChar));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
||||
@ -146,13 +153,13 @@ struct TChar
|
||||
// Windows uses UTF-16 encoding for wchar.
|
||||
else if constexpr (PLATFORM_WINDOWS && (CSameAs<FCharType, wchar>))
|
||||
{
|
||||
return TChar::IsNonch(static_cast<u16char>(InChar));
|
||||
return TChar<u16char>::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));
|
||||
return TChar<u32char>::IsNonch(static_cast<u32char>(InChar));
|
||||
}
|
||||
|
||||
else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
|
487
Redcraft.Utility/Source/Public/Strings/Convert.h
Normal file
487
Redcraft.Utility/Source/Public/Strings/Convert.h
Normal file
@ -0,0 +1,487 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Numerics/Limits.h"
|
||||
#include "Algorithms/Basic.h"
|
||||
#include "Memory/Allocators.h"
|
||||
#include "Memory/Address.h"
|
||||
#include "Containers/Array.h"
|
||||
#include "Strings/Char.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
#include <charconv>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
template <typename R>
|
||||
concept CStringRange = CInputRange<R> && CCharType<TRangeElement<R>>;
|
||||
|
||||
template <typename I>
|
||||
concept CStringIterator = CInputIterator<I> && CCharType<TIteratorElement<I>>;
|
||||
|
||||
NAMESPACE_BEGIN(Algorithms)
|
||||
|
||||
/**
|
||||
* Parses a boolean value from the given string range.
|
||||
* Ignore leading and trailing spaces and case-insensitive.
|
||||
*
|
||||
* - "True" become true.
|
||||
* - "False" become false.
|
||||
*
|
||||
* @param Range - The range of characters to parse.
|
||||
* @param Value - The boolean value to parse.
|
||||
*
|
||||
* @return true if the value is successfully parsed, false otherwise.
|
||||
*/
|
||||
template <CStringRange R>
|
||||
constexpr bool Parse(R&& Range, bool& Value)
|
||||
{
|
||||
using FCharTraits = TChar<TRangeElement<R>>;
|
||||
|
||||
if constexpr (CSizedRange<R&>)
|
||||
{
|
||||
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
||||
}
|
||||
|
||||
auto Iter = Ranges::Begin(Range);
|
||||
auto Sent = Ranges::End (Range);
|
||||
|
||||
bool Result;
|
||||
|
||||
// Ignore leading spaces.
|
||||
while (Iter != Sent && FCharTraits::IsSpace(*Iter)) ++Iter;
|
||||
|
||||
if (Iter == Sent) return false;
|
||||
|
||||
// Parse the true value.
|
||||
if (Iter != Sent && (*Iter == LITERAL(TRangeElement<R>, 't') || *Iter == LITERAL(TRangeElement<R>, 'T')))
|
||||
{
|
||||
++Iter;
|
||||
|
||||
Result = true;
|
||||
|
||||
if (Iter != Sent && (*Iter == LITERAL(TRangeElement<R>, 'r') || *Iter == LITERAL(TRangeElement<R>, 'R'))) ++Iter; else return false;
|
||||
if (Iter != Sent && (*Iter == LITERAL(TRangeElement<R>, 'u') || *Iter == LITERAL(TRangeElement<R>, 'U'))) ++Iter; else return false;
|
||||
if (Iter != Sent && (*Iter == LITERAL(TRangeElement<R>, 'e') || *Iter == LITERAL(TRangeElement<R>, 'E'))) ++Iter; else return false;
|
||||
}
|
||||
|
||||
// Parse the false value.
|
||||
else if (Iter != Sent && (*Iter == LITERAL(TRangeElement<R>, 'f') || *Iter == LITERAL(TRangeElement<R>, 'F')))
|
||||
{
|
||||
++Iter;
|
||||
|
||||
Result = false;
|
||||
|
||||
if (Iter != Sent && (*Iter == LITERAL(TRangeElement<R>, 'a') || *Iter == LITERAL(TRangeElement<R>, 'A'))) ++Iter; else return false;
|
||||
if (Iter != Sent && (*Iter == LITERAL(TRangeElement<R>, 'l') || *Iter == LITERAL(TRangeElement<R>, 'L'))) ++Iter; else return false;
|
||||
if (Iter != Sent && (*Iter == LITERAL(TRangeElement<R>, 's') || *Iter == LITERAL(TRangeElement<R>, 'S'))) ++Iter; else return false;
|
||||
if (Iter != Sent && (*Iter == LITERAL(TRangeElement<R>, 'e') || *Iter == LITERAL(TRangeElement<R>, 'E'))) ++Iter; else return false;
|
||||
}
|
||||
|
||||
else return false;
|
||||
|
||||
// Ignore trailing spaces.
|
||||
while (Iter != Sent && FCharTraits::IsSpace(*Iter)) ++Iter;
|
||||
|
||||
if (Iter != Sent) return false;
|
||||
|
||||
Value = Result;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a boolean value from the given string range.
|
||||
* Ignore leading and trailing spaces and case-insensitive.
|
||||
*
|
||||
* - "True" become true.
|
||||
* - "False" become false.
|
||||
*
|
||||
* @param First - The iterator of the range.
|
||||
* @param Last - The sentinel of the range.
|
||||
* @param Value - The boolean value to parse.
|
||||
*
|
||||
* @return true if the value is successfully parsed, false otherwise.
|
||||
*/
|
||||
template <CStringIterator I, CSentinelFor<I> S>
|
||||
FORCEINLINE constexpr bool Parse(I First, S Last, bool& Value)
|
||||
{
|
||||
if constexpr (CSizedSentinelFor<S, I>)
|
||||
{
|
||||
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
||||
}
|
||||
|
||||
return Algorithms::Parse(Ranges::View(MoveTemp(First), Last), Value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integral value from the given string range.
|
||||
* Ignore leading and trailing spaces and case-insensitive.
|
||||
* If the ingeter value is unsigned, the negative sign causes the parsing to fail.
|
||||
* Allow parsing base prefixes: "0x" for hexadecimal, "0b" for binary, and "0" for octal.
|
||||
*
|
||||
* @param Range - The range of characters to parse.
|
||||
* @param Value - The integral value to parse.
|
||||
* @param Base - The base of the number, between [2, 36], or 0 for auto-detect.
|
||||
*
|
||||
* @return true if the value is successfully parsed, false otherwise.
|
||||
*/
|
||||
template <CStringRange R, CIntegral T> requires (!CConst<T> && !CVolatile<T> && !CSameAs<T, bool>)
|
||||
constexpr bool Parse(R&& Range, T& Value, uint Base = 0)
|
||||
{
|
||||
using FCharTraits = TChar<TRangeElement<R>>;
|
||||
|
||||
checkf(Base == 0 || (Base >= 2 && Base <= 36), TEXT("Illegal base. Please check the Base."));
|
||||
|
||||
if constexpr (CSizedRange<R&>)
|
||||
{
|
||||
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
||||
}
|
||||
|
||||
auto Iter = Ranges::Begin(Range);
|
||||
auto Sent = Ranges::End (Range);
|
||||
|
||||
// Ignore leading spaces.
|
||||
while (Iter != Sent && FCharTraits::IsSpace(*Iter)) ++Iter;
|
||||
|
||||
if (Iter == Sent) return false;
|
||||
|
||||
bool bNegative = false;
|
||||
|
||||
// Parse the negative sign.
|
||||
if constexpr (CSigned<T>)
|
||||
{
|
||||
if (*Iter == LITERAL(TRangeElement<R>, '-'))
|
||||
{
|
||||
bNegative = true;
|
||||
++Iter;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the positive sign.
|
||||
if (!bNegative && *Iter == LITERAL(TRangeElement<R>, '+')) ++Iter;
|
||||
|
||||
// Auto-detect the base.
|
||||
if (Base == 0)
|
||||
{
|
||||
if (Iter == Sent) return false;
|
||||
|
||||
if (*Iter == LITERAL(TRangeElement<R>, '0'))
|
||||
{
|
||||
++Iter;
|
||||
|
||||
// Return zero if the string has only one zero.
|
||||
if (Iter == Sent || FCharTraits::IsSpace(*Iter))
|
||||
{
|
||||
while (Iter != Sent && FCharTraits::IsSpace(*Iter)) ++Iter;
|
||||
|
||||
if (Iter != Sent) return false;
|
||||
|
||||
Value = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*Iter == LITERAL(TRangeElement<R>, 'x') || *Iter == LITERAL(TRangeElement<R>, 'X'))
|
||||
{
|
||||
Base = 16;
|
||||
++Iter;
|
||||
}
|
||||
|
||||
else if (*Iter == LITERAL(TRangeElement<R>, 'b') || *Iter == LITERAL(TRangeElement<R>, 'B'))
|
||||
{
|
||||
Base = 2;
|
||||
++Iter;
|
||||
}
|
||||
|
||||
else if (FCharTraits::IsDigit(*Iter, 8)) Base = 8;
|
||||
|
||||
else return false;
|
||||
}
|
||||
|
||||
else Base = 10;
|
||||
}
|
||||
|
||||
// Parse the base prefix.
|
||||
else if (Base == 2 || Base == 16)
|
||||
{
|
||||
if (Iter == Sent) return false;
|
||||
|
||||
if (*Iter == LITERAL(TRangeElement<R>, '0'))
|
||||
{
|
||||
++Iter;
|
||||
|
||||
// Return zero if the string has only one zero.
|
||||
if (Iter == Sent || FCharTraits::IsSpace(*Iter))
|
||||
{
|
||||
while (Iter != Sent && FCharTraits::IsSpace(*Iter)) ++Iter;
|
||||
|
||||
if (Iter != Sent) return false;
|
||||
|
||||
Value = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Base == 16 && (*Iter == LITERAL(TRangeElement<R>, 'x') || *Iter == LITERAL(TRangeElement<R>, 'X'))) ++Iter;
|
||||
if (Base == 2 && (*Iter == LITERAL(TRangeElement<R>, 'b') || *Iter == LITERAL(TRangeElement<R>, 'B'))) ++Iter;
|
||||
}
|
||||
}
|
||||
|
||||
if (Iter == Sent) return false;
|
||||
|
||||
check(Base >= 2 && Base <= 36);
|
||||
|
||||
if (!FCharTraits::IsDigit(*Iter, Base)) return false;
|
||||
|
||||
using FUnsignedT = TMakeUnsigned<T>;
|
||||
|
||||
FUnsignedT LastValue = 0;
|
||||
FUnsignedT Unsigned = 0;
|
||||
|
||||
do
|
||||
{
|
||||
uint Digit = FCharTraits::ToDigit(*Iter);
|
||||
|
||||
// Break if the char is not a digit.
|
||||
if (Digit >= Base) break;
|
||||
|
||||
++Iter;
|
||||
|
||||
LastValue = Unsigned;
|
||||
|
||||
Unsigned = LastValue * Base + Digit;
|
||||
|
||||
// Fail if the value is overflowed.
|
||||
if (Unsigned < LastValue) return false;
|
||||
}
|
||||
while (Iter != Sent);
|
||||
|
||||
// Ignore trailing spaces.
|
||||
while (Iter != Sent && FCharTraits::IsSpace(*Iter)) ++Iter;
|
||||
|
||||
if (Iter != Sent) return false;
|
||||
|
||||
if constexpr (CSigned<T>)
|
||||
{
|
||||
// Fail if the value is overflowed.
|
||||
if (!bNegative && Unsigned >= static_cast<FUnsignedT>(TNumericLimits<T>::Max())) return false;
|
||||
if ( bNegative && Unsigned >= static_cast<FUnsignedT>(TNumericLimits<T>::Min())) return false;
|
||||
|
||||
// Reverse if the value is negative.
|
||||
if (bNegative) Unsigned = -Unsigned;
|
||||
}
|
||||
|
||||
Value = Unsigned;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integral value from the given string range.
|
||||
* Ignore leading and trailing spaces and case-insensitive.
|
||||
* If the ingeter value is unsigned, the negative sign causes the parsing to fail.
|
||||
* Allow parsing base prefixes: "0x" for hexadecimal, "0b" for binary, and "0" for octal.
|
||||
*
|
||||
* @param First - The iterator of the range.
|
||||
* @param Last - The sentinel of the range.
|
||||
* @param Value - The integral value to parse.
|
||||
* @param Base - The base of the number, between [2, 36], or 0 for auto-detect.
|
||||
*
|
||||
* @return true if the value is successfully parsed, false otherwise.
|
||||
*/
|
||||
template <CStringIterator I, CSentinelFor<I> S, CIntegral T> requires (!CConst<T> && !CVolatile<T> && !CSameAs<T, bool>)
|
||||
FORCEINLINE constexpr bool Parse(I First, S Last, T& Value, uint Base = 0)
|
||||
{
|
||||
if constexpr (CSizedSentinelFor<S, I>)
|
||||
{
|
||||
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
||||
}
|
||||
|
||||
return Algorithms::Parse(Ranges::View(MoveTemp(First), Last), Value, Base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a floating-point value from the given string range.
|
||||
* Ignore leading and trailing spaces and case-insensitive.
|
||||
* Automatically detect formats if multiple formats are allowed.
|
||||
* Allow parsing base prefixes: "0x" for hexadecimal.
|
||||
*
|
||||
* @param Range - The range of characters to parse.
|
||||
* @param Value - The floating-point value to parse.
|
||||
* @param bFixed - Allow parsing fixed-point values.
|
||||
* @param bScientific - Allow parsing scientific notation values.
|
||||
* @param bHex - Allow parsing hex floating-point values.
|
||||
*
|
||||
* @return true if the value is successfully parsed, false otherwise.
|
||||
*/
|
||||
template <CStringRange R, CFloatingPoint T> requires (!CConst<T> && !CVolatile<T>)
|
||||
constexpr bool Parse(R&& Range, T& Value, bool bFixed = true, bool bScientific = true, bool bHex = true)
|
||||
{
|
||||
if (!bFixed && !bScientific && !bHex) return false;
|
||||
|
||||
using FCharTraits = TChar<TRangeElement<R>>;
|
||||
|
||||
if constexpr (CSizedRange<R&>)
|
||||
{
|
||||
checkf(Algorithms::Distance(Range) >= 0, TEXT("Illegal range. Please check Algorithms::Distance(Range)."));
|
||||
}
|
||||
|
||||
auto Iter = Ranges::Begin(Range);
|
||||
auto Sent = Ranges::End (Range);
|
||||
|
||||
// Ignore leading spaces.
|
||||
while (Iter != Sent && FCharTraits::IsSpace(*Iter)) ++Iter;
|
||||
|
||||
if (Iter == Sent) return false;
|
||||
|
||||
bool bNegative = false;
|
||||
|
||||
// Parse the negative sign.
|
||||
if (*Iter == LITERAL(TRangeElement<R>, '-'))
|
||||
{
|
||||
bNegative = true;
|
||||
++Iter;
|
||||
}
|
||||
|
||||
// Parse the positive sign.
|
||||
else if (*Iter == LITERAL(TRangeElement<R>, '+')) ++Iter;
|
||||
|
||||
if (Iter == Sent) return false;
|
||||
|
||||
// Fail if the string has multiple signs.
|
||||
if (*Iter == LITERAL(TRangeElement<R>, '-')) return false;
|
||||
if (*Iter == LITERAL(TRangeElement<R>, '+')) return false;
|
||||
|
||||
NAMESPACE_STD::chars_format Format = NAMESPACE_STD::chars_format::general;
|
||||
|
||||
if ( bFixed && !bScientific) Format = NAMESPACE_STD::chars_format::fixed;
|
||||
else if (!bFixed && bScientific) Format = NAMESPACE_STD::chars_format::scientific;
|
||||
else if (!bFixed && !bScientific) Format = NAMESPACE_STD::chars_format::hex;
|
||||
|
||||
// Auto-detect the hex format.
|
||||
if (bHex)
|
||||
{
|
||||
if (*Iter == LITERAL(TRangeElement<R>, '0'))
|
||||
{
|
||||
++Iter;
|
||||
|
||||
// Return zero if the string has only one zero.
|
||||
if (Iter == Sent || FCharTraits::IsSpace(*Iter))
|
||||
{
|
||||
while (Iter != Sent && FCharTraits::IsSpace(*Iter)) ++Iter;
|
||||
|
||||
if (Iter != Sent) return false;
|
||||
|
||||
Value = static_cast<T>(bNegative ? -0.0 : 0.0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*Iter == LITERAL(TRangeElement<R>, 'x') || *Iter == LITERAL(TRangeElement<R>, 'X'))
|
||||
{
|
||||
Format = NAMESPACE_STD::chars_format::hex;
|
||||
++Iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Iter == Sent) return false;
|
||||
|
||||
T Result;
|
||||
|
||||
// Copy to a buffer if the range is not contiguous.
|
||||
if constexpr (!CContiguousRange<R> || !CSameAs<TRangeElement<R>, char>)
|
||||
{
|
||||
TArray<char, TInlineAllocator<64>> Buffer;
|
||||
|
||||
for (; Iter != Sent; ++Iter)
|
||||
{
|
||||
auto Char = *Iter;
|
||||
|
||||
// Ignore trailing spaces.
|
||||
if (FCharTraits::IsSpace(Char)) break;
|
||||
|
||||
// Assert that floating-point values must be represented by ASCII.
|
||||
if (FCharTraits::IsASCII(Char)) Buffer.PushBack(static_cast<char>(Char));
|
||||
|
||||
else return false;
|
||||
}
|
||||
|
||||
const char* First = Buffer.GetData();
|
||||
const char* Last = Buffer.GetData() + Buffer.Num();
|
||||
|
||||
NAMESPACE_STD::from_chars_result ConvertResult = NAMESPACE_STD::from_chars(First, Last, Result, Format);
|
||||
|
||||
if (ConvertResult.ec == NAMESPACE_STD::errc::result_out_of_range) return false;
|
||||
if (ConvertResult.ec == NAMESPACE_STD::errc::invalid_argument) return false;
|
||||
|
||||
// Assert that the buffer is fully parsed.
|
||||
if (ConvertResult.ptr != Last) return false;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
const char* First = ToAddress(Iter);
|
||||
const char* Last = ToAddress(Iter) + Algorithms::Distance(Iter, Sent);
|
||||
|
||||
NAMESPACE_STD::from_chars_result ConvertResult = NAMESPACE_STD::from_chars(First, Last, Result, Format);
|
||||
|
||||
if (ConvertResult.ec == NAMESPACE_STD::errc::result_out_of_range) return false;
|
||||
if (ConvertResult.ec == NAMESPACE_STD::errc::invalid_argument) return false;
|
||||
|
||||
// Move the iterator to the end of the parsed value.
|
||||
Algorithms::Advance(Iter, ConvertResult.ptr - First);
|
||||
}
|
||||
|
||||
// Ignore trailing spaces.
|
||||
while (Iter != Sent && FCharTraits::IsSpace(*Iter)) ++Iter;
|
||||
|
||||
if (Iter != Sent) return false;
|
||||
|
||||
Value = bNegative ? -Result : Result;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a floating-point value from the given string range.
|
||||
* Ignore leading and trailing spaces and case-insensitive.
|
||||
* Automatically detect formats if multiple formats are allowed.
|
||||
* Allow parsing base prefixes: "0x" for hexadecimal.
|
||||
*
|
||||
* @param First - The iterator of the range.
|
||||
* @param Last - The sentinel of the range.
|
||||
* @param Value - The floating-point value to parse.
|
||||
* @param bFixed - Allow parsing fixed-point values.
|
||||
* @param bScientific - Allow parsing scientific notation values.
|
||||
* @param bHex - Allow parsing hex floating-point values.
|
||||
*
|
||||
* @return true if the value is successfully parsed, false otherwise.
|
||||
*/
|
||||
template <CStringIterator I, CSentinelFor<I> S, CFloatingPoint T> requires (!CConst<T> && !CVolatile<T>)
|
||||
FORCEINLINE constexpr bool Parse(I First, S Last, T& Value, bool bFixed = true, bool bScientific = true, bool bHex = true)
|
||||
{
|
||||
if constexpr (CSizedSentinelFor<S, I>)
|
||||
{
|
||||
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
|
||||
}
|
||||
|
||||
return Algorithms::Parse(Ranges::View(MoveTemp(First), Last), Value, bFixed, bScientific, bHex);
|
||||
}
|
||||
|
||||
NAMESPACE_END(Algorithms)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
||||
|
||||
#pragma warning(pop)
|
3183
Redcraft.Utility/Source/Public/Strings/Formatting.h
Normal file
3183
Redcraft.Utility/Source/Public/Strings/Formatting.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -5,16 +5,18 @@
|
||||
#include "Templates/Utility.h"
|
||||
#include "Templates/TypeHash.h"
|
||||
#include "Templates/Optional.h"
|
||||
#include "Memory/Allocator.h"
|
||||
#include "Memory/Allocators.h"
|
||||
#include "Containers/Array.h"
|
||||
#include "Containers/ArrayView.h"
|
||||
#include "Iterator/Utility.h"
|
||||
#include "Iterator/BasicIterator.h"
|
||||
#include "Iterator/Sentinel.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Range/Factory.h"
|
||||
#include "String/Char.h"
|
||||
#include "String/StringView.h"
|
||||
#include "Iterators/Utility.h"
|
||||
#include "Iterators/Sentinel.h"
|
||||
#include "Iterators/BasicIterator.h"
|
||||
#include "Iterators/InsertIterator.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Ranges/Factory.h"
|
||||
#include "Strings/Char.h"
|
||||
#include "Strings/StringView.h"
|
||||
#include "Strings/Formatting.h"
|
||||
#include "Miscellaneous/AssertionMacros.h"
|
||||
|
||||
#include <locale>
|
||||
@ -93,7 +95,7 @@ public:
|
||||
/** Constructs the string with the contents of the range. */
|
||||
template <CInputRange R> requires (!CSameAs<TRemoveCVRef<R>, TString>
|
||||
&& !CSameAs<TRemoveCVRef<R>, TStringView<FElementType>> && CConstructibleFrom<FElementType, TRangeReference<R>>)
|
||||
FORCEINLINE explicit TString(R&& Range) : TString(Range::Begin(Range), Range::End(Range)) { }
|
||||
FORCEINLINE explicit TString(R&& Range) : TString(Ranges::Begin(Range), Ranges::End(Range)) { }
|
||||
|
||||
/** Copy constructor. Constructs the string with the copy of the contents of 'InValue'. */
|
||||
FORCEINLINE TString(const TString&) = default;
|
||||
@ -102,7 +104,7 @@ public:
|
||||
FORCEINLINE TString(TString&&) = default;
|
||||
|
||||
/** Constructs the string with the contents of the initializer list. */
|
||||
FORCEINLINE TString(initializer_list<FElementType> IL) : TString(Range::Begin(IL), Range::End(IL)) { }
|
||||
FORCEINLINE TString(initializer_list<FElementType> IL) : TString(Ranges::Begin(IL), Ranges::End(IL)) { }
|
||||
|
||||
/** Copy assignment operator. Replaces the contents with a copy of the contents of 'InValue'. */
|
||||
FORCEINLINE TString& operator=(const TString&) = default;
|
||||
@ -249,7 +251,7 @@ public:
|
||||
void StableErase(...) = delete;
|
||||
|
||||
/** Appends 'Count' copies of the 'InValue' to the end of the string. */
|
||||
TString& Append(size_t Count, FElementType InChar) { return Append(Range::Repeat(InChar, Count)); }
|
||||
TString& Append(size_t Count, FElementType InChar) { return Append(Ranges::Repeat(InChar, Count)); }
|
||||
|
||||
/** Appends the contents of the range ['InPtr', 'InPtr' + 'Count') to the end of the string. */
|
||||
FORCEINLINE TString& Append(const FElementType* InPtr, size_t Count) { return Append(TStringView<FElementType>(InPtr, Count)); }
|
||||
@ -296,10 +298,10 @@ public:
|
||||
|
||||
/** Appends the contents of the range to the end of the string. */
|
||||
template <CInputRange R> requires (CConstructibleFrom<FElementType, TRangeReference<R>>)
|
||||
FORCEINLINE TString& Append(R&& Range) { return Append(Range::Begin(Range), Range::End(Range)); }
|
||||
FORCEINLINE TString& Append(R&& Range) { return Append(Ranges::Begin(Range), Ranges::End(Range)); }
|
||||
|
||||
/** Appends the contents of the initializer list to the end of the string. */
|
||||
FORCEINLINE TString& Append(initializer_list<FElementType> IL) { return Append(Range::Begin(IL), Range::End(IL)); }
|
||||
FORCEINLINE TString& Append(initializer_list<FElementType> IL) { return Append(Ranges::Begin(IL), Ranges::End(IL)); }
|
||||
|
||||
/** Appends the given character value to the end of the string. */
|
||||
FORCEINLINE TString& operator+=(FElementType InChar) { return Append(1, InChar); }
|
||||
@ -470,7 +472,7 @@ public:
|
||||
{
|
||||
checkf(this->IsValidIterator(First) && this->IsValidIterator(Last) && First <= Last, TEXT("Read access violation. Please check IsValidIterator()."));
|
||||
|
||||
return Replace(First, Last, Range::Repeat(InChar, Count));
|
||||
return Replace(First, Last, Ranges::Repeat(InChar, Count));
|
||||
}
|
||||
|
||||
/** Replace the substring [Index, Index + CountToReplace) with the contents of the ['InPtr', 'InPtr' + 'Count'). */
|
||||
@ -599,7 +601,7 @@ public:
|
||||
{
|
||||
checkf(this->IsValidIterator(First) && this->IsValidIterator(Last) && First <= Last, TEXT("Read access violation. Please check IsValidIterator()."));
|
||||
|
||||
return Replace(First, Last, Range::Begin(Range), Range::End(Range));
|
||||
return Replace(First, Last, Ranges::Begin(Range), Ranges::End(Range));
|
||||
}
|
||||
|
||||
/** Replace the substring [Index, Index + CountToReplace) with the contents of the initializer list. */
|
||||
@ -615,7 +617,7 @@ public:
|
||||
{
|
||||
checkf(this->IsValidIterator(First) && this->IsValidIterator(Last) && First <= Last, TEXT("Read access violation. Please check IsValidIterator()."));
|
||||
|
||||
return Replace(First, Last, Range::Begin(IL), Range::End(IL));
|
||||
return Replace(First, Last, Ranges::Begin(IL), Ranges::End(IL));
|
||||
}
|
||||
|
||||
/** Obtains a string that is a view over the 'Count' characters of this string view starting at 'Offset'. */
|
||||
@ -808,7 +810,7 @@ public:
|
||||
|
||||
do
|
||||
{
|
||||
const auto Result = Facet.in(State, BeginFrom, EndFrom, NextFrom, Range::Begin(Buffer), Range::End(Buffer), NextTo);
|
||||
const auto Result = Facet.in(State, BeginFrom, EndFrom, NextFrom, Ranges::Begin(Buffer), Ranges::End(Buffer), NextTo);
|
||||
|
||||
if (BeginFrom == NextFrom) return false;
|
||||
|
||||
@ -856,7 +858,7 @@ public:
|
||||
|
||||
do
|
||||
{
|
||||
const auto Result = Facet.out(State, BeginFrom, EndFrom, NextFrom, Range::Begin(Buffer), Range::End(Buffer), NextTo);
|
||||
const auto Result = Facet.out(State, BeginFrom, EndFrom, NextFrom, Ranges::Begin(Buffer), Ranges::End(Buffer), NextTo);
|
||||
|
||||
if (BeginFrom == NextFrom) return false;
|
||||
|
||||
@ -1122,10 +1124,7 @@ public:
|
||||
/** @return The non-modifiable standard C character string version of the string. */
|
||||
NODISCARD FORCEINLINE auto operator*() &&
|
||||
{
|
||||
if (this->Back() != LITERAL(T, '\0'))
|
||||
{
|
||||
this->PushBack(LITERAL(T, '\0'));
|
||||
}
|
||||
if (!EndsWith(LITERAL(T, '\0'))) this->PushBack(LITERAL(T, '\0'));
|
||||
|
||||
return AsConst(*this).GetData();
|
||||
}
|
||||
@ -1144,22 +1143,64 @@ public:
|
||||
return TStringView<FElementType>(*this).IsASCII();
|
||||
}
|
||||
|
||||
/** @return true if the string can be fully represented as a boolean value, false otherwise. */
|
||||
/** @return true if the string can be converted to a boolean value, false otherwise. */
|
||||
NODISCARD FORCEINLINE bool IsBoolean() const
|
||||
{
|
||||
return TStringView<FElementType>(*this).IsBoolean();
|
||||
}
|
||||
|
||||
/** @return true if the string can be fully represented as an integer value, false otherwise. */
|
||||
NODISCARD FORCEINLINE bool IsInteger(unsigned Base = 10, bool bSigned = true) const
|
||||
/** @return true if the string can be converted to an integer value, false otherwise. */
|
||||
template <CIntegral U = int> requires (!CSameAs<U, bool> && CSameAs<TRemoveCVRef<U>, U>)
|
||||
NODISCARD FORCEINLINE bool IsInteger(uint Base = 0) const
|
||||
{
|
||||
return TStringView<FElementType>(*this).IsInteger(Base, bSigned);
|
||||
return TStringView<FElementType>(*this).template IsInteger<U>(Base);
|
||||
}
|
||||
|
||||
/** @return true if the string can be fully represented as a floating-point value, false otherwise. */
|
||||
NODISCARD FORCEINLINE bool IsFloatingPoint(bool bFixed = true, bool bScientific = true, bool bSigned = true) const
|
||||
/** @return true if the string can be converted to a floating-point value, false otherwise. */
|
||||
template <CFloatingPoint U = float> requires (!CSameAs<U, bool> && CSameAs<TRemoveCVRef<U>, U>)
|
||||
NODISCARD FORCEINLINE bool IsFloatingPoint(bool bFixed = true, bool bScientific = true, bool bHex = true) const
|
||||
{
|
||||
return TStringView<FElementType>(*this).IsFloatingPoint(bFixed, bScientific, bSigned);
|
||||
return TStringView<FElementType>(*this).template IsFloatingPoint<U>(bFixed, bScientific, bHex);
|
||||
}
|
||||
|
||||
/** Converts the string into a boolean value. */
|
||||
NODISCARD FORCEINLINE constexpr bool ToBool() const
|
||||
{
|
||||
return TStringView<FElementType>(*this).ToBool();
|
||||
}
|
||||
|
||||
/** Converts the string into an integer value. */
|
||||
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||
NODISCARD FORCEINLINE constexpr U ToInt(uint Base = 0) const
|
||||
{
|
||||
return TStringView<FElementType>(*this).template ToInt<U>(Base);
|
||||
}
|
||||
|
||||
/** Converts the string into a floating-point value. */
|
||||
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||
NODISCARD FORCEINLINE constexpr U ToFloat(bool bFixed = true, bool bScientific = true, bool bHex = true) const
|
||||
{
|
||||
return TStringView<FElementType>(*this).template ToFloat<U>(bFixed, bScientific, bHex);
|
||||
}
|
||||
|
||||
/** Parse the string into a boolean value. */
|
||||
NODISCARD FORCEINLINE constexpr bool Parse(bool& Value)
|
||||
{
|
||||
return TStringView<FElementType>(*this).Parse(Value);
|
||||
}
|
||||
|
||||
/** Parse the string into an integer value. */
|
||||
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||
NODISCARD FORCEINLINE constexpr bool Parse(U& Value, uint Base = 0)
|
||||
{
|
||||
return TStringView<FElementType>(*this).Parse(Value, Base);
|
||||
}
|
||||
|
||||
/** Parse the string into a floating-point value. */
|
||||
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||
NODISCARD FORCEINLINE constexpr bool Parse(U& Value, bool bFixed = true, bool bScientific = true, bool bHex = true)
|
||||
{
|
||||
return TStringView<FElementType>(*this).Parse(Value, bFixed, bScientific, bHex);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1189,7 +1230,7 @@ public:
|
||||
* @return The string containing the integer value.
|
||||
*/
|
||||
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||
NODISCARD static FORCEINLINE TString FromInt(U Value, unsigned Base = 10)
|
||||
NODISCARD static FORCEINLINE TString FromInt(U Value, uint Base = 10)
|
||||
{
|
||||
checkf(Base >= 2 && Base <= 36, TEXT("Illegal base. Please check the base."));
|
||||
|
||||
@ -1247,7 +1288,7 @@ public:
|
||||
* @return
|
||||
*/
|
||||
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||
NODISCARD static FORCEINLINE TString FromFloat(U Value, bool bFixed, bool bScientific, unsigned Precision)
|
||||
NODISCARD static FORCEINLINE TString FromFloat(U Value, bool bFixed, bool bScientific, uint Precision)
|
||||
{
|
||||
TString Result;
|
||||
|
||||
@ -1257,121 +1298,83 @@ public:
|
||||
}
|
||||
|
||||
/** Converts a boolean value into a string and appends it to the string. */
|
||||
void AppendBool(bool Value);
|
||||
FORCEINLINE void AppendBool(bool Value)
|
||||
{
|
||||
auto Inserter = Ranges::View(MakeBackInserter(*this), UnreachableSentinel);
|
||||
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0}"), Value);
|
||||
}
|
||||
|
||||
/** Converts an integer value into a string and appends it to the string. */
|
||||
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||
void AppendInt(U Value, unsigned Base = 10);
|
||||
FORCEINLINE void AppendInt(U Value, uint Base = 10)
|
||||
{
|
||||
auto Inserter = Ranges::View(MakeBackInserter(*this), UnreachableSentinel);
|
||||
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0:_{1}I}"), Value, Base);
|
||||
}
|
||||
|
||||
/** Converts a floating-point value into a string and appends it to the string. */
|
||||
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||
void AppendFloat(U Value);
|
||||
FORCEINLINE void AppendFloat(U Value)
|
||||
{
|
||||
auto Inserter = Ranges::View(MakeBackInserter(*this), UnreachableSentinel);
|
||||
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0}"), Value);
|
||||
}
|
||||
|
||||
/** Converts a floating-point value into a string and appends it to the string. */
|
||||
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||
void AppendFloat(U Value, bool bFixed, bool bScientific);
|
||||
FORCEINLINE void AppendFloat(U Value, bool bFixed, bool bScientific)
|
||||
{
|
||||
auto Inserter = Ranges::View(MakeBackInserter(*this), UnreachableSentinel);
|
||||
|
||||
if (bFixed && bScientific)
|
||||
{
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0:G}"), Value);
|
||||
}
|
||||
|
||||
else if (bFixed)
|
||||
{
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0:F}"), Value);
|
||||
}
|
||||
|
||||
else if (bScientific)
|
||||
{
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0:E}"), Value);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0:A}"), Value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts a floating-point value into a string and appends it to the string. */
|
||||
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||
void AppendFloat(U Value, bool bFixed, bool bScientific, unsigned Precision);
|
||||
|
||||
/**
|
||||
* 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 FORCEINLINE bool ToBool() const
|
||||
FORCEINLINE void AppendFloat(U Value, bool bFixed, bool bScientific, uint Precision)
|
||||
{
|
||||
return TStringView<FElementType>(*this).ToBool();
|
||||
}
|
||||
auto Inserter = Ranges::View(MakeBackInserter(*this), UnreachableSentinel);
|
||||
|
||||
/**
|
||||
* 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 FORCEINLINE U ToInt(unsigned Base = 10) const
|
||||
{
|
||||
checkf(Base >= 2 && Base <= 36, TEXT("Illegal base. Please check the base."));
|
||||
if (bFixed && bScientific)
|
||||
{
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0:.{1}G}"), Value, Precision);
|
||||
}
|
||||
|
||||
return TStringView<FElementType>(*this).template ToInt<U>(Base);
|
||||
}
|
||||
else if (bFixed)
|
||||
{
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0:.{1}F}"), Value, Precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 FORCEINLINE U ToFloat(bool bFixed = true, bool bScientific = false) const
|
||||
{
|
||||
return TStringView<FElementType>(*this).template ToFloat<U>(bFixed, bScientific);
|
||||
}
|
||||
else if (bScientific)
|
||||
{
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0:.{1}E}"), Value, Precision);
|
||||
}
|
||||
|
||||
/** Converts a string into a boolean value and remove the parsed substring. */
|
||||
NODISCARD FORCEINLINE bool ToBoolAndTrim()
|
||||
{
|
||||
TStringView<FElementType> View = *this;
|
||||
|
||||
bool Result = View.ToBoolAndTrim();
|
||||
|
||||
size_t TrimNum = this->Num() - View.Num();
|
||||
|
||||
if (TrimNum > 0) Erase(0, TrimNum);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/** Converts a string into an integer value and remove the parsed substring. */
|
||||
template <CIntegral U = int> requires (!CSameAs<U, bool> && !CConst<U> && !CVolatile<U>)
|
||||
NODISCARD FORCEINLINE U ToIntAndTrim(unsigned Base = 10)
|
||||
{
|
||||
TStringView<FElementType> View = *this;
|
||||
|
||||
U Result = View.template ToIntAndTrim<U>(Base);
|
||||
|
||||
size_t TrimNum = this->Num() - View.Num();
|
||||
|
||||
if (TrimNum > 0) Erase(0, TrimNum);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/** Converts a string into a floating-point value and remove the parsed substring. */
|
||||
template <CFloatingPoint U = float> requires (!CConst<U> && !CVolatile<U>)
|
||||
NODISCARD FORCEINLINE U ToFloatAndTrim(bool bFixed = true, bool bScientific = true)
|
||||
{
|
||||
TStringView<FElementType> View = *this;
|
||||
|
||||
U Result = View.template ToFloatAndTrim<U>(bFixed, bScientific);
|
||||
|
||||
size_t TrimNum = this->Num() - View.Num();
|
||||
|
||||
if (TrimNum > 0) Erase(0, TrimNum);
|
||||
|
||||
return Result;
|
||||
else
|
||||
{
|
||||
Algorithms::Format(Inserter, LITERAL_VIEW(FElementType, "{0:.{1}A}"), Value, Precision);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1396,35 +1399,11 @@ public:
|
||||
|
||||
/** Format some objects using a format string and append to the string. */
|
||||
template <typename... Ts>
|
||||
void AppendFormat(TStringView<FElementType> Fmt, const Ts&... Args);
|
||||
|
||||
/**
|
||||
* 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>
|
||||
FORCEINLINE size_t Parse(TStringView<FElementType> Fmt, Ts&... Args) const
|
||||
FORCEINLINE void AppendFormat(TStringView<FElementType> Fmt, const Ts&... Args)
|
||||
{
|
||||
return TStringView(*this).Parse(Fmt, Args...);
|
||||
}
|
||||
auto Inserter = Ranges::View(MakeBackInserter(*this), UnreachableSentinel);
|
||||
|
||||
/** Parse a string using a format string to objects and remove the parsed substring. */
|
||||
template <typename... Ts>
|
||||
FORCEINLINE size_t ParseAndTrim(TStringView<FElementType> Fmt, Ts&... Args)
|
||||
{
|
||||
TStringView<FElementType> View = *this;
|
||||
|
||||
size_t Result = View.ParseAndTrim(Fmt, Args...);
|
||||
|
||||
size_t TrimNum = this->Num() - View.Num();
|
||||
|
||||
if (TrimNum > 0) Erase(0, TrimNum);
|
||||
|
||||
return Result;
|
||||
Algorithms::Format(Inserter, Fmt, Args...);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1460,10 +1439,68 @@ using FU32String = TString<u32char>;
|
||||
using FUnicodeString = TString<unicodechar>;
|
||||
|
||||
template <CCharType T> template <typename Allocator> constexpr TStringView<T>::TStringView(const TString<FElementType, Allocator>& InString)
|
||||
: TStringView(InString.GetData(), InString.Num()) { }
|
||||
: TStringView(InString.GetData(), InString.Num())
|
||||
{ }
|
||||
|
||||
/**
|
||||
* A formatter for TString.
|
||||
*
|
||||
* The syntax of format specifications is:
|
||||
*
|
||||
* [Fill And Align] [Width] [Precision] [Type] [!] [?]
|
||||
*
|
||||
* 1. The fill and align part:
|
||||
*
|
||||
* [Fill Character] <Align Option>
|
||||
*
|
||||
* i. Fill Character: The character is used to fill width of the object. It is optional and cannot be '{' or '}'.
|
||||
* It should be representable as a single unicode otherwise it is undefined behavior.
|
||||
*
|
||||
* ii. Align Option: The character is used to indicate the direction of alignment.
|
||||
*
|
||||
* - '<': Align the formatted argument to the left of the available space
|
||||
* by inserting n fill characters after the formatted argument.
|
||||
* This is default option.
|
||||
* - '^': Align the formatted argument to the center of the available space
|
||||
* by inserting n fill characters around the formatted argument.
|
||||
* If cannot absolute centering, offset to the left.
|
||||
* - '>': Align the formatted argument ro the right of the available space
|
||||
* by inserting n fill characters before the formatted argument.
|
||||
*
|
||||
* 2. The width part:
|
||||
*
|
||||
* - 'N': The number is used to specify the minimum field width of the object.
|
||||
* N should be an unsigned non-zero decimal number.
|
||||
* - '{N}': Dynamically determine the minimum field width of the object.
|
||||
* N should be a valid index of the format integral argument.
|
||||
* N is optional, and the default value is automatic indexing.
|
||||
*
|
||||
* 3. The precision part:
|
||||
*
|
||||
* - '.N': The number is used to specify the maximum field width of the object.
|
||||
* N should be an unsigned non-zero decimal number.
|
||||
* - '.{N}': Dynamically determine the maximum field width of the object.
|
||||
* N should be a valid index of the format integral argument.
|
||||
* N is optional, and the default value is automatic indexing.
|
||||
*
|
||||
* 4. The type indicator part:
|
||||
*
|
||||
* - none: Indicates the as-is formatting.
|
||||
* - 'S': Indicates the as-is formatting.
|
||||
* - 's': Indicates lowercase formatting.
|
||||
*
|
||||
* 5. The case indicators part:
|
||||
*
|
||||
* - '!': Indicates capitalize the entire string.
|
||||
*
|
||||
* 6. The escape indicators part:
|
||||
*
|
||||
* - '?': Indicates the escape formatting.
|
||||
*
|
||||
*/
|
||||
template <CCharType T, typename Allocator>
|
||||
class TFormatter<TString<T, Allocator>, T> : public TFormatter<TStringView<T>, T> { };
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
||||
|
||||
#include "String/Conversion.h.inl"
|
1278
Redcraft.Utility/Source/Public/Strings/StringView.h
Normal file
1278
Redcraft.Utility/Source/Public/Strings/StringView.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -94,18 +94,6 @@ FORCEINLINE constexpr TReferenceWrapper<T> Ref(TReferenceWrapper<T> InValue)
|
||||
return Ref(InValue.Get());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCEINLINE constexpr TReferenceWrapper<const T> Ref(const T& InValue)
|
||||
{
|
||||
return TReferenceWrapper<const T>(InValue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCEINLINE constexpr TReferenceWrapper<const T> Ref(TReferenceWrapper<T> InValue)
|
||||
{
|
||||
return Ref(InValue.Get());
|
||||
}
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <typename T> struct TIsTReferenceWrapperImpl : FFalse { };
|
||||
|
@ -278,28 +278,37 @@ struct TTTupleSynthThreeWayComparable<TTypeSequence<>, TTypeSequence<>> : FTrue
|
||||
template <typename TSequence, typename USequence>
|
||||
concept CTTupleSynthThreeWayComparable = TTTupleSynthThreeWayComparable<TSequence, USequence>::Value;
|
||||
|
||||
template <typename Ret, typename Indices>
|
||||
struct TTupleVisitElementByIndex;
|
||||
|
||||
template <typename Ret, size_t I, size_t... Indices>
|
||||
struct TTupleVisitElementByIndex<Ret, TIndexSequence<I, Indices...>>
|
||||
template <typename Ret, typename F, typename TTupleType>
|
||||
struct TTupleVisitElementByIndex
|
||||
{
|
||||
template <typename F, typename TTupleType>
|
||||
FORCEINLINE static constexpr decltype(auto) Do(F&& Func, TTupleType&& Arg, size_t Index)
|
||||
template <size_t Index>
|
||||
struct TInvokeElement
|
||||
{
|
||||
if (Index == I) return InvokeResult<Ret>(Forward<F>(Func), Forward<TTupleType>(Arg).template GetValue<I>());
|
||||
return TTupleVisitElementByIndex<Ret, TIndexSequence<Indices...>>::Do(Forward<F>(Func), Forward<TTupleType>(Arg), Index);
|
||||
}
|
||||
};
|
||||
FORCEINLINE static constexpr Ret Do(F&& Func, TTupleType&& Arg)
|
||||
{
|
||||
return InvokeResult<Ret>(Forward<F>(Func), Forward<TTupleType>(Arg).template GetValue<Index>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Ret>
|
||||
struct TTupleVisitElementByIndex<Ret, TIndexSequence<>>
|
||||
{
|
||||
template <typename F, typename TTupleType>
|
||||
FORCEINLINE static constexpr decltype(auto) Do(F&& Func, TTupleType&& Arg, size_t)
|
||||
template <typename>
|
||||
struct TInvokeTuple;
|
||||
|
||||
template <size_t... Indices>
|
||||
struct TInvokeTuple<TIndexSequence<Indices...>>
|
||||
{
|
||||
checkf(false, "Read access violation. Please check Index.");
|
||||
return InvokeResult<Ret>(Forward<F>(Func), Forward<TTupleType>(Arg).template GetValue<0>());
|
||||
FORCEINLINE static constexpr Ret Do(F&& Func, TTupleType&& Arg, size_t Index)
|
||||
{
|
||||
using FInvokeImplType = Ret(*)(F&&, TTupleType&&);
|
||||
|
||||
constexpr FInvokeImplType InvokeImpl[] = { TInvokeElement<Indices>::Do... };
|
||||
|
||||
return InvokeImpl[Index](Forward<F>(Func), Forward<TTupleType>(Arg));
|
||||
}
|
||||
};
|
||||
|
||||
FORCEINLINE static constexpr Ret Do(F&& Func, TTupleType&& Arg, size_t Index)
|
||||
{
|
||||
return TInvokeTuple<TMakeIndexSequence<Arg.Num()>>::Do(Forward<F>(Func), Forward<TTupleType>(Arg), Index);
|
||||
}
|
||||
};
|
||||
|
||||
@ -421,64 +430,64 @@ public:
|
||||
template <typename T> NODISCARD FORCEINLINE constexpr decltype(auto) GetValue() const volatile&& { return static_cast<const volatile TTuple&&>(*this).GetValue<TTupleIndex<T, TTuple>>(); }
|
||||
|
||||
/** Invoke the callable object 'Func' with a tuple of arguments. */
|
||||
template <typename F> requires (CInvocable<F, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) & { return FHelper::Apply(Forward<F>(Func), static_cast< TTuple& >(*this)); }
|
||||
template <typename F> requires (CInvocable<F, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const & { return FHelper::Apply(Forward<F>(Func), static_cast<const TTuple& >(*this)); }
|
||||
template <typename F> requires (CInvocable<F, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) volatile& { return FHelper::Apply(Forward<F>(Func), static_cast< volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (CInvocable<F, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const volatile& { return FHelper::Apply(Forward<F>(Func), static_cast<const volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (CInvocable<F, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) && { return FHelper::Apply(Forward<F>(Func), static_cast< TTuple&&>(*this)); }
|
||||
template <typename F> requires (CInvocable<F, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const && { return FHelper::Apply(Forward<F>(Func), static_cast<const TTuple&&>(*this)); }
|
||||
template <typename F> requires (CInvocable<F, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) volatile&& { return FHelper::Apply(Forward<F>(Func), static_cast< volatile TTuple&&>(*this)); }
|
||||
template <typename F> requires (CInvocable<F, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const volatile&& { return FHelper::Apply(Forward<F>(Func), static_cast<const volatile TTuple&&>(*this)); }
|
||||
template <typename F> requires (CInvocable<F&&, Ts& ...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) & { return FHelper::Apply(Forward<F>(Func), static_cast< TTuple& >(*this)); }
|
||||
template <typename F> requires (CInvocable<F&&, const Ts& ...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const & { return FHelper::Apply(Forward<F>(Func), static_cast<const TTuple& >(*this)); }
|
||||
template <typename F> requires (CInvocable<F&&, volatile Ts& ...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) volatile& { return FHelper::Apply(Forward<F>(Func), static_cast< volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (CInvocable<F&&, const volatile Ts& ...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const volatile& { return FHelper::Apply(Forward<F>(Func), static_cast<const volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (CInvocable<F&&, Ts&&...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) && { return FHelper::Apply(Forward<F>(Func), static_cast< TTuple&&>(*this)); }
|
||||
template <typename F> requires (CInvocable<F&&, const Ts&&...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const && { return FHelper::Apply(Forward<F>(Func), static_cast<const TTuple&&>(*this)); }
|
||||
template <typename F> requires (CInvocable<F&&, volatile Ts&&...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) volatile&& { return FHelper::Apply(Forward<F>(Func), static_cast< volatile TTuple&&>(*this)); }
|
||||
template <typename F> requires (CInvocable<F&&, const volatile Ts&&...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const volatile&& { return FHelper::Apply(Forward<F>(Func), static_cast<const volatile TTuple&&>(*this)); }
|
||||
|
||||
/** Visits each element in a tuple in parallel and applies it as arguments to the function. */
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>) FORCEINLINE constexpr void Visit(F&& Func) & { VisitTuple(Forward<F>(Func), static_cast< TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>) FORCEINLINE constexpr void Visit(F&& Func) const & { VisitTuple(Forward<F>(Func), static_cast<const TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>) FORCEINLINE constexpr void Visit(F&& Func) volatile& { VisitTuple(Forward<F>(Func), static_cast< volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>) FORCEINLINE constexpr void Visit(F&& Func) const volatile& { VisitTuple(Forward<F>(Func), static_cast<const volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>) FORCEINLINE constexpr void Visit(F&& Func) && { VisitTuple(Forward<F>(Func), static_cast< TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>) FORCEINLINE constexpr void Visit(F&& Func) const && { VisitTuple(Forward<F>(Func), static_cast<const TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>) FORCEINLINE constexpr void Visit(F&& Func) volatile&& { VisitTuple(Forward<F>(Func), static_cast< volatile TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F, Ts>) FORCEINLINE constexpr void Visit(F&& Func) const volatile&& { VisitTuple(Forward<F>(Func), static_cast<const volatile TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F&&, Ts& >) FORCEINLINE constexpr void Visit(F&& Func) & { VisitTuple(Forward<F>(Func), static_cast< TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F&&, const Ts& >) FORCEINLINE constexpr void Visit(F&& Func) const & { VisitTuple(Forward<F>(Func), static_cast<const TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F&&, volatile Ts& >) FORCEINLINE constexpr void Visit(F&& Func) volatile& { VisitTuple(Forward<F>(Func), static_cast< volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F&&, const volatile Ts& >) FORCEINLINE constexpr void Visit(F&& Func) const volatile& { VisitTuple(Forward<F>(Func), static_cast<const volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F&&, Ts&&>) FORCEINLINE constexpr void Visit(F&& Func) && { VisitTuple(Forward<F>(Func), static_cast< TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F&&, const Ts&&>) FORCEINLINE constexpr void Visit(F&& Func) const && { VisitTuple(Forward<F>(Func), static_cast<const TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F&&, volatile Ts&&>) FORCEINLINE constexpr void Visit(F&& Func) volatile&& { VisitTuple(Forward<F>(Func), static_cast< volatile TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && CInvocable<F&&, const volatile Ts&&>) FORCEINLINE constexpr void Visit(F&& Func) const volatile&& { VisitTuple(Forward<F>(Func), static_cast<const volatile TTuple&&>(*this)); }
|
||||
|
||||
/** Visits specified element in a tuple and applies it as arguments to the function. */
|
||||
template <typename F> requires ((sizeof...(Ts) >= 1 && CCommonType<TInvokeResult<F, Ts>...>) && ... && (CInvocable<F, Ts>)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) & { return static_cast< TTuple& >(*this).Visit<TCommonType<TInvokeResult<F, Ts>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires ((sizeof...(Ts) >= 1 && CCommonType<TInvokeResult<F, Ts>...>) && ... && (CInvocable<F, Ts>)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const & { return static_cast<const TTuple& >(*this).Visit<TCommonType<TInvokeResult<F, Ts>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires ((sizeof...(Ts) >= 1 && CCommonType<TInvokeResult<F, Ts>...>) && ... && (CInvocable<F, Ts>)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) volatile& { return static_cast< volatile TTuple& >(*this).Visit<TCommonType<TInvokeResult<F, Ts>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires ((sizeof...(Ts) >= 1 && CCommonType<TInvokeResult<F, Ts>...>) && ... && (CInvocable<F, Ts>)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const volatile& { return static_cast<const volatile TTuple& >(*this).Visit<TCommonType<TInvokeResult<F, Ts>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires ((sizeof...(Ts) >= 1 && CCommonType<TInvokeResult<F, Ts>...>) && ... && (CInvocable<F, Ts>)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) && { return static_cast< TTuple&&>(*this).Visit<TCommonType<TInvokeResult<F, Ts>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires ((sizeof...(Ts) >= 1 && CCommonType<TInvokeResult<F, Ts>...>) && ... && (CInvocable<F, Ts>)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const && { return static_cast<const TTuple&&>(*this).Visit<TCommonType<TInvokeResult<F, Ts>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires ((sizeof...(Ts) >= 1 && CCommonType<TInvokeResult<F, Ts>...>) && ... && (CInvocable<F, Ts>)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) volatile&& { return static_cast< volatile TTuple&&>(*this).Visit<TCommonType<TInvokeResult<F, Ts>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires ((sizeof...(Ts) >= 1 && CCommonType<TInvokeResult<F, Ts>...>) && ... && (CInvocable<F, Ts>)) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const volatile&& { return static_cast<const volatile TTuple&&>(*this).Visit<TCommonType<TInvokeResult<F, Ts>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires (((sizeof...(Ts) >= 1) && ... && CInvocable<F&&, Ts& >) && CCommonReference<TInvokeResult<F&&, Ts& >...>) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) & { checkf(Index < Num(), "Read access violation. Please check Index."); return static_cast< TTuple& >(*this).Visit<TCommonReference<TInvokeResult<F&&, Ts& >...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires (((sizeof...(Ts) >= 1) && ... && CInvocable<F&&, const Ts& >) && CCommonReference<TInvokeResult<F&&, const Ts& >...>) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const & { checkf(Index < Num(), "Read access violation. Please check Index."); return static_cast<const TTuple& >(*this).Visit<TCommonReference<TInvokeResult<F&&, const Ts& >...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires (((sizeof...(Ts) >= 1) && ... && CInvocable<F&&, volatile Ts& >) && CCommonReference<TInvokeResult<F&&, volatile Ts& >...>) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) volatile& { checkf(Index < Num(), "Read access violation. Please check Index."); return static_cast< volatile TTuple& >(*this).Visit<TCommonReference<TInvokeResult<F&&, volatile Ts& >...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires (((sizeof...(Ts) >= 1) && ... && CInvocable<F&&, const volatile Ts& >) && CCommonReference<TInvokeResult<F&&, const volatile Ts& >...>) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const volatile& { checkf(Index < Num(), "Read access violation. Please check Index."); return static_cast<const volatile TTuple& >(*this).Visit<TCommonReference<TInvokeResult<F&&, const volatile Ts& >...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires (((sizeof...(Ts) >= 1) && ... && CInvocable<F&&, Ts&&>) && CCommonReference<TInvokeResult<F&&, Ts&&>...>) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) && { checkf(Index < Num(), "Read access violation. Please check Index."); return static_cast< TTuple&&>(*this).Visit<TCommonReference<TInvokeResult<F&&, Ts&&>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires (((sizeof...(Ts) >= 1) && ... && CInvocable<F&&, const Ts&&>) && CCommonReference<TInvokeResult<F&&, const Ts&&>...>) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const && { checkf(Index < Num(), "Read access violation. Please check Index."); return static_cast<const TTuple&&>(*this).Visit<TCommonReference<TInvokeResult<F&&, const Ts&&>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires (((sizeof...(Ts) >= 1) && ... && CInvocable<F&&, volatile Ts&&>) && CCommonReference<TInvokeResult<F&&, volatile Ts&&>...>) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) volatile&& { checkf(Index < Num(), "Read access violation. Please check Index."); return static_cast< volatile TTuple&&>(*this).Visit<TCommonReference<TInvokeResult<F&&, volatile Ts&&>...>>(Forward<F>(Func), Index); }
|
||||
template <typename F> requires (((sizeof...(Ts) >= 1) && ... && CInvocable<F&&, const volatile Ts&&>) && CCommonReference<TInvokeResult<F&&, const volatile Ts&&>...>) FORCEINLINE constexpr decltype(auto) Visit(F&& Func, size_t Index) const volatile&& { checkf(Index < Num(), "Read access violation. Please check Index."); return static_cast<const volatile TTuple&&>(*this).Visit<TCommonReference<TInvokeResult<F&&, const volatile Ts&&>...>>(Forward<F>(Func), Index); }
|
||||
|
||||
/** Visits specified element in a tuple and applies it as arguments to the function. */
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F, Ts>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) & { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, TMakeIndexSequence<sizeof...(Ts)>>::Do(Forward<F>(Func), static_cast< TTuple& >(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F, Ts>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const & { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, TMakeIndexSequence<sizeof...(Ts)>>::Do(Forward<F>(Func), static_cast<const TTuple& >(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F, Ts>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) volatile& { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, TMakeIndexSequence<sizeof...(Ts)>>::Do(Forward<F>(Func), static_cast< volatile TTuple& >(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F, Ts>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const volatile& { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, TMakeIndexSequence<sizeof...(Ts)>>::Do(Forward<F>(Func), static_cast<const volatile TTuple& >(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F, Ts>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) && { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, TMakeIndexSequence<sizeof...(Ts)>>::Do(Forward<F>(Func), static_cast< TTuple&&>(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F, Ts>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const && { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, TMakeIndexSequence<sizeof...(Ts)>>::Do(Forward<F>(Func), static_cast<const TTuple&&>(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F, Ts>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) volatile&& { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, TMakeIndexSequence<sizeof...(Ts)>>::Do(Forward<F>(Func), static_cast< volatile TTuple&&>(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F, Ts>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const volatile&& { return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, TMakeIndexSequence<sizeof...(Ts)>>::Do(Forward<F>(Func), static_cast<const volatile TTuple&&>(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F&&, Ts& >) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) & { checkf(Index < Num(), "Read access violation. Please check Index."); return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, F, TTuple& >::Do(Forward<F>(Func), static_cast< TTuple& >(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F&&, const Ts& >) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const & { checkf(Index < Num(), "Read access violation. Please check Index."); return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, F, const TTuple& >::Do(Forward<F>(Func), static_cast<const TTuple& >(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F&&, volatile Ts& >) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) volatile& { checkf(Index < Num(), "Read access violation. Please check Index."); return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, F, volatile TTuple& >::Do(Forward<F>(Func), static_cast< volatile TTuple& >(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F&&, const volatile Ts& >) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const volatile& { checkf(Index < Num(), "Read access violation. Please check Index."); return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, F, const volatile TTuple& >::Do(Forward<F>(Func), static_cast<const volatile TTuple& >(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F&&, Ts&&>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) && { checkf(Index < Num(), "Read access violation. Please check Index."); return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, F, TTuple&&>::Do(Forward<F>(Func), static_cast< TTuple&&>(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F&&, const Ts&&>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const && { checkf(Index < Num(), "Read access violation. Please check Index."); return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, F, const TTuple&&>::Do(Forward<F>(Func), static_cast<const TTuple&&>(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F&&, volatile Ts&&>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) volatile&& { checkf(Index < Num(), "Read access violation. Please check Index."); return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, F, volatile TTuple&&>::Do(Forward<F>(Func), static_cast< volatile TTuple&&>(*this), Index); }
|
||||
template <typename Ret, typename F> requires ((sizeof...(Ts) >= 1) && ... && CInvocableResult<Ret, F&&, const volatile Ts&&>) FORCEINLINE constexpr Ret Visit(F&& Func, size_t Index) const volatile&& { checkf(Index < Num(), "Read access violation. Please check Index."); return NAMESPACE_PRIVATE::TTupleVisitElementByIndex<Ret, F, const volatile TTuple&&>::Do(Forward<F>(Func), static_cast<const volatile TTuple&&>(*this), Index); }
|
||||
|
||||
/** Transform a tuple into another tuple using the given function. */
|
||||
template <typename F> requires (true && ... && (CInvocable<F, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) & { return FHelper::Transform(Forward<F>(Func), static_cast< TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const & { return FHelper::Transform(Forward<F>(Func), static_cast<const TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) volatile& { return FHelper::Transform(Forward<F>(Func), static_cast< volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const volatile& { return FHelper::Transform(Forward<F>(Func), static_cast<const volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) && { return FHelper::Transform(Forward<F>(Func), static_cast< TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const && { return FHelper::Transform(Forward<F>(Func), static_cast<const TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) volatile&& { return FHelper::Transform(Forward<F>(Func), static_cast< volatile TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const volatile&& { return FHelper::Transform(Forward<F>(Func), static_cast<const volatile TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F&&, Ts& > && !CSameAs<void, TInvokeResult<F&&, Ts& >>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) & { return FHelper::Transform(Forward<F>(Func), static_cast< TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F&&, const Ts& > && !CSameAs<void, TInvokeResult<F&&, const Ts& >>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const & { return FHelper::Transform(Forward<F>(Func), static_cast<const TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F&&, volatile Ts& > && !CSameAs<void, TInvokeResult<F&&, volatile Ts& >>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) volatile& { return FHelper::Transform(Forward<F>(Func), static_cast< volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F&&, const volatile Ts& > && !CSameAs<void, TInvokeResult<F&&, const volatile Ts& >>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const volatile& { return FHelper::Transform(Forward<F>(Func), static_cast<const volatile TTuple& >(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F&&, Ts&&> && !CSameAs<void, TInvokeResult<F&&, Ts&&>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) && { return FHelper::Transform(Forward<F>(Func), static_cast< TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F&&, const Ts&&> && !CSameAs<void, TInvokeResult<F&&, const Ts&&>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const && { return FHelper::Transform(Forward<F>(Func), static_cast<const TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F&&, volatile Ts&&> && !CSameAs<void, TInvokeResult<F&&, volatile Ts&&>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) volatile&& { return FHelper::Transform(Forward<F>(Func), static_cast< volatile TTuple&&>(*this)); }
|
||||
template <typename F> requires (true && ... && (CInvocable<F&&, const volatile Ts&&> && !CSameAs<void, TInvokeResult<F&&, const volatile Ts&&>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const volatile&& { return FHelper::Transform(Forward<F>(Func), static_cast<const volatile TTuple&&>(*this)); }
|
||||
|
||||
/** Constructs an object of type T with a tuple as an argument. */
|
||||
template <typename T> requires (CConstructibleFrom<T, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() & { return FHelper::template Construct<T>(static_cast< TTuple& >(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() const & { return FHelper::template Construct<T>(static_cast<const TTuple& >(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() volatile& { return FHelper::template Construct<T>(static_cast< volatile TTuple& >(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() const volatile& { return FHelper::template Construct<T>(static_cast<const volatile TTuple& >(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() && { return FHelper::template Construct<T>(static_cast< TTuple&&>(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() const && { return FHelper::template Construct<T>(static_cast<const TTuple&&>(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() volatile&& { return FHelper::template Construct<T>(static_cast< volatile TTuple&&>(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() const volatile&& { return FHelper::template Construct<T>(static_cast<const volatile TTuple&&>(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, Ts& ...>) NODISCARD FORCEINLINE constexpr T Construct() & { return FHelper::template Construct<T>(static_cast< TTuple& >(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, const Ts& ...>) NODISCARD FORCEINLINE constexpr T Construct() const & { return FHelper::template Construct<T>(static_cast<const TTuple& >(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, volatile Ts& ...>) NODISCARD FORCEINLINE constexpr T Construct() volatile& { return FHelper::template Construct<T>(static_cast< volatile TTuple& >(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, const volatile Ts& ...>) NODISCARD FORCEINLINE constexpr T Construct() const volatile& { return FHelper::template Construct<T>(static_cast<const volatile TTuple& >(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, Ts&&...>) NODISCARD FORCEINLINE constexpr T Construct() && { return FHelper::template Construct<T>(static_cast< TTuple&&>(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, const Ts&&...>) NODISCARD FORCEINLINE constexpr T Construct() const && { return FHelper::template Construct<T>(static_cast<const TTuple&&>(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, volatile Ts&&...>) NODISCARD FORCEINLINE constexpr T Construct() volatile&& { return FHelper::template Construct<T>(static_cast< volatile TTuple&&>(*this)); }
|
||||
template <typename T> requires (CConstructibleFrom<T, const volatile Ts&&...>) NODISCARD FORCEINLINE constexpr T Construct() const volatile&& { return FHelper::template Construct<T>(static_cast<const volatile TTuple&&>(*this)); }
|
||||
|
||||
/** @return The number of elements in the tuple. */
|
||||
NODISCARD static FORCEINLINE constexpr size_t Num() { return sizeof...(Ts); }
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Range/Utility.h"
|
||||
#include "Ranges/Utility.h"
|
||||
#include "Templates/Meta.h"
|
||||
#include "Templates/Invoke.h"
|
||||
#include "Templates/Utility.h"
|
||||
@ -433,11 +433,11 @@ private:
|
||||
using FMoveAssignImpl = void(*)(void*, void*);
|
||||
using FDestroyImpl = void(*)(void* );
|
||||
|
||||
static constexpr FCopyConstructImpl CopyConstructImpl[] = { [](void* A, const void* B) { if constexpr (requires(Ts* A, const Ts* B) { Memory::CopyConstruct (A, B); }) Memory::CopyConstruct (reinterpret_cast<Ts*>(A), reinterpret_cast<const Ts*>(B)); else checkf(false, TEXT("The type '%s' is not copy constructible."), typeid(Ts).name()); }... };
|
||||
static constexpr FMoveConstructImpl MoveConstructImpl[] = { [](void* A, void* B) { if constexpr (requires(Ts* A, Ts* B) { Memory::MoveConstruct (A, B); }) Memory::MoveConstruct (reinterpret_cast<Ts*>(A), reinterpret_cast< Ts*>(B)); else checkf(false, TEXT("The type '%s' is not move constructible."), typeid(Ts).name()); }... };
|
||||
static constexpr FCopyAssignImpl CopyAssignImpl[] = { [](void* A, const void* B) { if constexpr (requires(Ts* A, const Ts* B) { Memory::CopyAssign (A, B); }) Memory::CopyAssign (reinterpret_cast<Ts*>(A), reinterpret_cast<const Ts*>(B)); else checkf(false, TEXT("The type '%s' is not copy assignable."), typeid(Ts).name()); }... };
|
||||
static constexpr FMoveAssignImpl MoveAssignImpl[] = { [](void* A, void* B) { if constexpr (requires(Ts* A, Ts* B) { Memory::MoveAssign (A, B); }) Memory::MoveAssign (reinterpret_cast<Ts*>(A), reinterpret_cast< Ts*>(B)); else checkf(false, TEXT("The type '%s' is not move assignable."), typeid(Ts).name()); }... };
|
||||
static constexpr FDestroyImpl DestroyImpl[] = { [](void* A ) { if constexpr (requires(Ts* A ) { Memory::Destruct (A ); }) Memory::Destruct (reinterpret_cast<Ts*>(A) ); else checkf(false, TEXT("The type '%s' is not destructible."), typeid(Ts).name()); }... };
|
||||
static constexpr FCopyConstructImpl CopyConstructImpl[] = { [](void* A, const void* B) { if constexpr (requires(Ts* A, const Ts* B) { Memory::CopyConstruct (A, B); }) Memory::CopyConstruct (static_cast<Ts*>(A), static_cast<const Ts*>(B)); else checkf(false, TEXT("The type '%s' is not copy constructible."), typeid(Ts).name()); }... };
|
||||
static constexpr FMoveConstructImpl MoveConstructImpl[] = { [](void* A, void* B) { if constexpr (requires(Ts* A, Ts* B) { Memory::MoveConstruct (A, B); }) Memory::MoveConstruct (static_cast<Ts*>(A), static_cast< Ts*>(B)); else checkf(false, TEXT("The type '%s' is not move constructible."), typeid(Ts).name()); }... };
|
||||
static constexpr FCopyAssignImpl CopyAssignImpl[] = { [](void* A, const void* B) { if constexpr (requires(Ts* A, const Ts* B) { Memory::CopyAssign (A, B); }) Memory::CopyAssign (static_cast<Ts*>(A), static_cast<const Ts*>(B)); else checkf(false, TEXT("The type '%s' is not copy assignable."), typeid(Ts).name()); }... };
|
||||
static constexpr FMoveAssignImpl MoveAssignImpl[] = { [](void* A, void* B) { if constexpr (requires(Ts* A, Ts* B) { Memory::MoveAssign (A, B); }) Memory::MoveAssign (static_cast<Ts*>(A), static_cast< Ts*>(B)); else checkf(false, TEXT("The type '%s' is not move assignable."), typeid(Ts).name()); }... };
|
||||
static constexpr FDestroyImpl DestroyImpl[] = { [](void* A ) { if constexpr (requires(Ts* A ) { Memory::Destruct (A ); }) Memory::Destruct (static_cast<Ts*>(A) ); else checkf(false, TEXT("The type '%s' is not destructible."), typeid(Ts).name()); }... };
|
||||
|
||||
TAlignedUnion<1, Ts...> Value;
|
||||
uint8 TypeIndex;
|
||||
@ -479,7 +479,7 @@ struct TVariantVisitImpl
|
||||
for (size_t Index = 0; Index < sizeof...(VariantTypes); ++Index)
|
||||
{
|
||||
Result *= VariantNums[Index];
|
||||
Result += Range::Begin(Indices)[Index];
|
||||
Result += Ranges::Begin(Indices)[Index];
|
||||
}
|
||||
|
||||
return Result;
|
||||
@ -502,10 +502,10 @@ struct TVariantVisitImpl
|
||||
};
|
||||
|
||||
template <size_t EncodedIndex, typename>
|
||||
struct FInvokeEncoded;
|
||||
struct TInvokeEncoded;
|
||||
|
||||
template <size_t EncodedIndex, size_t... ExtentIndices>
|
||||
struct FInvokeEncoded<EncodedIndex, TIndexSequence<ExtentIndices...>>
|
||||
struct TInvokeEncoded<EncodedIndex, TIndexSequence<ExtentIndices...>>
|
||||
{
|
||||
FORCEINLINE static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
@ -513,7 +513,7 @@ struct TVariantVisitImpl
|
||||
}
|
||||
|
||||
template <typename Ret>
|
||||
struct FResult
|
||||
struct TResult
|
||||
{
|
||||
FORCEINLINE static constexpr Ret Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
@ -523,26 +523,26 @@ struct TVariantVisitImpl
|
||||
};
|
||||
|
||||
template <typename>
|
||||
struct FInvokeVariant;
|
||||
struct TInvokeVariant;
|
||||
|
||||
template <size_t... EncodedIndices>
|
||||
struct FInvokeVariant<TIndexSequence<EncodedIndices...>>
|
||||
struct TInvokeVariant<TIndexSequence<EncodedIndices...>>
|
||||
{
|
||||
FORCEINLINE static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
using FExtentIndices = TIndexSequenceFor<VariantTypes...>;
|
||||
|
||||
using FResultType = TCommonType<decltype(FInvokeEncoded<EncodedIndices, FExtentIndices>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...))...>;
|
||||
using FResultType = TCommonReference<decltype(TInvokeEncoded<EncodedIndices, FExtentIndices>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...))...>;
|
||||
|
||||
using FInvokeImplType = FResultType(*)(F&&, VariantTypes&&...);
|
||||
|
||||
constexpr FInvokeImplType InvokeImpl[] = { FInvokeEncoded<EncodedIndices, FExtentIndices>::template FResult<FResultType>::Do... };
|
||||
constexpr FInvokeImplType InvokeImpl[] = { TInvokeEncoded<EncodedIndices, FExtentIndices>::template TResult<FResultType>::Do... };
|
||||
|
||||
return InvokeImpl[FEncodeIndices::Do({ Variants.GetIndex()... })](Forward<F>(Func), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
|
||||
template <typename Ret>
|
||||
struct FResult
|
||||
struct TResult
|
||||
{
|
||||
FORCEINLINE static constexpr Ret Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
@ -550,7 +550,7 @@ struct TVariantVisitImpl
|
||||
|
||||
using FInvokeImplType = Ret(*)(F&&, VariantTypes&&...);
|
||||
|
||||
constexpr FInvokeImplType InvokeImpl[] = { FInvokeEncoded<EncodedIndices, FExtentIndices>::template FResult<Ret>::Do... };
|
||||
constexpr FInvokeImplType InvokeImpl[] = { TInvokeEncoded<EncodedIndices, FExtentIndices>::template TResult<Ret>::Do... };
|
||||
|
||||
return InvokeImpl[FEncodeIndices::Do({ Variants.GetIndex()... })](Forward<F>(Func), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
@ -559,15 +559,15 @@ struct TVariantVisitImpl
|
||||
|
||||
FORCEINLINE static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
return FInvokeVariant<TMakeIndexSequence<FGetTotalNum::Do()>>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...);
|
||||
return TInvokeVariant<TMakeIndexSequence<FGetTotalNum::Do()>>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
|
||||
template <typename Ret>
|
||||
struct FResult
|
||||
struct TResult
|
||||
{
|
||||
FORCEINLINE static constexpr Ret Do(F&& Func, VariantTypes&&... Variants)
|
||||
{
|
||||
return FInvokeVariant<TMakeIndexSequence<FGetTotalNum::Do()>>::template FResult<Ret>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...);
|
||||
return TInvokeVariant<TMakeIndexSequence<FGetTotalNum::Do()>>::template TResult<Ret>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -589,7 +589,7 @@ template <typename Ret, typename F, typename FirstVariantType, typename... Varia
|
||||
constexpr Ret Visit(F&& Func, FirstVariantType&& FirstVariant, VariantTypes&&... Variants)
|
||||
{
|
||||
checkf((true && ... && Variants.IsValid()), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid()."));
|
||||
return NAMESPACE_PRIVATE::TVariantVisitImpl<F, FirstVariantType, VariantTypes...>::template FResult<Ret>::Do(Forward<F>(Func), Forward<FirstVariantType>(FirstVariant), Forward<VariantTypes>(Variants)...);
|
||||
return NAMESPACE_PRIVATE::TVariantVisitImpl<F, FirstVariantType, VariantTypes...>::template TResult<Ret>::Do(Forward<F>(Func), Forward<FirstVariantType>(FirstVariant), Forward<VariantTypes>(Variants)...);
|
||||
}
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
|
@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
REDCRAFTUTILITY_API void TestContainers();
|
||||
REDCRAFTUTILITY_API void TestArray();
|
||||
REDCRAFTUTILITY_API void TestStaticArray();
|
||||
REDCRAFTUTILITY_API void TestArrayView();
|
||||
REDCRAFTUTILITY_API void TestBitset();
|
||||
REDCRAFTUTILITY_API void TestStaticBitset();
|
||||
REDCRAFTUTILITY_API void TestList();
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
REDCRAFTUTILITY_API void TestMemory();
|
||||
REDCRAFTUTILITY_API void TestAddress();
|
||||
REDCRAFTUTILITY_API void TestAlignment();
|
||||
REDCRAFTUTILITY_API void TestMemoryBuffer();
|
||||
REDCRAFTUTILITY_API void TestMemoryMalloc();
|
||||
REDCRAFTUTILITY_API void TestMemoryOperator();
|
||||
REDCRAFTUTILITY_API void TestPointerTraits();
|
||||
REDCRAFTUTILITY_API void TestUniquePointer();
|
||||
REDCRAFTUTILITY_API void TestSharedPointer();
|
||||
REDCRAFTUTILITY_API void TestObserverPointer();
|
||||
REDCRAFTUTILITY_API void TestInOutPointer();
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
REDCRAFTUTILITY_API void TestMiscellaneous();
|
||||
REDCRAFTUTILITY_API void TestAssertionMacros();
|
||||
REDCRAFTUTILITY_API void TestCompare();
|
||||
REDCRAFTUTILITY_API void TestVarArgs();
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
REDCRAFTUTILITY_API void TestNumeric();
|
||||
REDCRAFTUTILITY_API void TestLiteral();
|
||||
REDCRAFTUTILITY_API void TestBit();
|
||||
REDCRAFTUTILITY_API void TestMath();
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,21 +0,0 @@
|
||||
#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();
|
||||
REDCRAFTUTILITY_API void TestStringView();
|
||||
REDCRAFTUTILITY_API void TestTemplateString();
|
||||
REDCRAFTUTILITY_API void TestStringConversion();
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
REDCRAFTUTILITY_API void TestTemplates();
|
||||
REDCRAFTUTILITY_API void TestInvoke();
|
||||
REDCRAFTUTILITY_API void TestReferenceWrapper();
|
||||
REDCRAFTUTILITY_API void TestOptional();
|
||||
REDCRAFTUTILITY_API void TestVariant();
|
||||
REDCRAFTUTILITY_API void TestAny();
|
||||
REDCRAFTUTILITY_API void TestTuple();
|
||||
REDCRAFTUTILITY_API void TestFunction();
|
||||
REDCRAFTUTILITY_API void TestAtomic();
|
||||
REDCRAFTUTILITY_API void TestScopeHelper();
|
||||
REDCRAFTUTILITY_API void TestPropagateConst();
|
||||
REDCRAFTUTILITY_API void TestMiscTemplates();
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
26
Redcraft.Utility/Source/Public/Testing/Testing.h
Normal file
26
Redcraft.Utility/Source/Public/Testing/Testing.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
REDCRAFTUTILITY_API void TestTypeTraits();
|
||||
REDCRAFTUTILITY_API void TestTemplates();
|
||||
REDCRAFTUTILITY_API void TestNumeric();
|
||||
REDCRAFTUTILITY_API void TestIterator();
|
||||
REDCRAFTUTILITY_API void TestRange();
|
||||
REDCRAFTUTILITY_API void TestAlgorithms();
|
||||
REDCRAFTUTILITY_API void TestMemory();
|
||||
REDCRAFTUTILITY_API void TestContainers();
|
||||
REDCRAFTUTILITY_API void TestString();
|
||||
REDCRAFTUTILITY_API void TestMiscellaneous();
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||
NAMESPACE_MODULE_BEGIN(Utility)
|
||||
|
||||
NAMESPACE_BEGIN(Testing)
|
||||
|
||||
REDCRAFTUTILITY_API void TestTypeTraits();
|
||||
|
||||
NAMESPACE_END(Testing)
|
||||
|
||||
NAMESPACE_MODULE_END(Utility)
|
||||
NAMESPACE_MODULE_END(Redcraft)
|
||||
NAMESPACE_REDCRAFT_END
|
Reference in New Issue
Block a user