Compare commits

..

73 Commits

Author SHA1 Message Date
6cc31f660c style(miscellaneous): add comments to the file system operation functions 2025-01-24 18:27:34 +08:00
2d79e18b25 fix(strings): fix access out-of-bounds when converting zero-length strings to null-terminated strings 2025-01-24 18:20:06 +08:00
1d5a61f308 feat(miscellaneous): add file system operation functions 2025-01-24 18:17:50 +08:00
38e1c3f8b7 feat(miscellaneous): add byte and text file access functions 2025-01-22 21:44:40 +08:00
8d3fa1ac98 feat(miscellaneous): add console operation functions 2025-01-20 12:04:57 +08:00
88e330336a refactor(strings): suppress compilation warnings from formatting tools 2025-01-20 12:04:16 +08:00
eca0d90d98 feat(miscellaneous): add enum class bitwise operation macro tools 2025-01-17 16:30:16 +08:00
d8adf47d10 feat(strings): add formatter for TStringView and TString 2025-01-15 19:33:13 +08:00
8a834a9c05 perf(strings): optimize formatting algorithm function 2025-01-15 17:04:05 +08:00
35f0ba71ab refactor(strings): replace and remove deprecated formatting tools 2025-01-14 22:28:52 +08:00
db7a40cb30 fix(strings): fix unexpected infinite recursion in TChar 2025-01-14 22:21:18 +08:00
6a70f0c501 fix(strings): fix treating boolean type as integral arguments 2025-01-14 22:19:12 +08:00
5629e31d49 fix(strings): fix string literal encoding types in formatting 2025-01-14 22:15:06 +08:00
c16da1af53 feat(strings): add formatter for pointer or member pointer types 2025-01-14 21:53:52 +08:00
88aba14620 fix(strings): fix dynamic formatting arguments not working 2025-01-14 17:53:16 +08:00
23963e0389 refactor(strings): refactor zero padding to make it more flexible 2025-01-14 17:39:19 +08:00
0c6f33762a fix(strings): fix incorrect treating 'A' as decimal number 2025-01-14 16:55:06 +08:00
9024957ff2 feat(strings): add formatter for floating-point types 2025-01-14 16:47:39 +08:00
68cd2c310a fix(strings): fix fill character cannot be defaulted 2025-01-07 22:09:53 +08:00
594acf219a feat(strings): add formatter for integral like types 2025-01-07 21:57:04 +08:00
e498b39d3d refactor(strings): refactor format string rules to make it more flexible 2025-01-04 21:51:35 +08:00
9dd5e74788 feat(strings): add a more general string formatting framework 2025-01-03 01:15:16 +08:00
c596882c32 feat(strings): add TChar::IsValid() support for char type 2025-01-03 01:14:09 +08:00
0e7ee5cde2 fix(templates): fix TTuple requires and implementations to avoid compilation failures 2025-01-03 01:12:39 +08:00
39d12bd7e4 refactor(templates): make TVariant conform to the style for general type identifiers 2025-01-03 01:10:04 +08:00
319d1cc8cb fix(ranges): fix TRangeView to be able to hold output iterator 2025-01-03 01:07:15 +08:00
fc87332845 fix(iterators): fix insert iterators to be assignable 2025-01-03 01:05:35 +08:00
22952237df fix(templates): fix the return value type of TTuple::Visit 2024-12-28 09:36:20 +08:00
f817afe6df fix(algorithms): fix compilation error on GCC for concept instantiation 2024-12-25 18:17:04 +08:00
a3cebf03ec refactor(strings): refactor and simplify string parsing functions 2024-12-25 18:15:46 +08:00
262ce1bb67 feat(ranges): add Ranges::AppendTo() function 2024-12-24 13:15:34 +08:00
bf22397123 feat(algorithms): add search algorithm and the corresponding testing 2024-12-22 17:55:11 +08:00
2de1068ad8 fix(templates): fix Ref() call ambiguity 2024-12-22 17:27:32 +08:00
aa572542e2 fix(algorithms): fix requires for Algorithms::Distance() 2024-12-22 15:21:09 +08:00
db855d27a1 style(ranges): clarify the semantic requirements of CRange and CSizedRange 2024-12-22 11:11:56 +08:00
04bb4be901 feat(algorithms): add more iterator algorithm and the corresponding testing 2024-12-21 21:35:59 +08:00
a68a6d16b6 refactor(numerics): refactor the numerics implementation folder to plural form 2024-12-21 21:21:59 +08:00
a92422e8b2 refactor(*): refactor the tool library's namespace to plural form 2024-12-20 18:09:27 +08:00
343007ffd6 feat(algorithms): add basic iterator algorithm and the corresponding testing 2024-12-20 17:35:31 +08:00
8c228fbf52 refactor(*): refactor the tool library's parent folder to plural form 2024-12-20 17:31:52 +08:00
a14fbd90db test(range): add test for range library 2024-12-20 15:35:44 +08:00
1e6beb83f2 refactor(testing): refactor test code and file to reduce the name collisions 2024-12-19 22:02:13 +08:00
7fb116c577 fix(*): fix ambiguity in NAMESPACE_PRIVATE when expanding macros 2024-12-19 21:53:04 +08:00
566052c8c2 fix(iterator): fix some iterator adapter implementation bugs 2024-12-19 20:48:21 +08:00
a0250ebaf8 test(iterator): add test for iterator library 2024-12-19 20:47:44 +08:00
f88cf7ef3e feat(range): add TTakeWhileView adapter 2024-12-19 14:35:45 +08:00
e6d525f2c3 feat(range): add simple view concept and refactor related requires 2024-12-19 12:04:22 +08:00
dd3a366c14 fix(*): fix some iterator adapter implementation bugs 2024-12-19 11:49:13 +08:00
85199119b3 fix(range): fix GetBase() of sentinel adapters such as TFilterView's 2024-12-18 21:45:25 +08:00
78d4955e03 fix(iterator): fix TCountedIterator not initializing Length 2024-12-18 21:42:10 +08:00
8f36410346 feat(range): add TTakeView adapter 2024-12-18 21:29:44 +08:00
87e48e5ca1 style(*): fix some comments and static_assert errors 2024-12-18 21:21:10 +08:00
93b3a17f06 fix(range): fix implementation of IBasicViewInterface 2024-12-18 21:20:11 +08:00
6ea768781d style(range): fix comment noun error 2024-12-18 17:38:05 +08:00
dff6050a3b feat(range): add TMoveView adapter 2024-12-18 17:13:11 +08:00
ae964ebd0a refactor(*): refactor files that depend on iterator and range with minimal #include 2024-12-18 16:58:43 +08:00
8be89d0bbc refactor(containers): refactor TArray's constructors and member functions 2024-12-18 12:14:59 +08:00
80238de712 refactor(containers): disable container element types with cv-qualifiers 2024-12-18 11:31:44 +08:00
f54386d102 fix(templates): fix recursive #include due to native array swap function 2024-12-17 22:14:00 +08:00
6a37e91639 refactor(*): replace the old with the new iterator and range library 2024-12-17 21:49:37 +08:00
0a37460f24 fix(range): fix range adapter closure behavior 2024-12-17 16:58:23 +08:00
aa8cd7ed33 feat(range): add range conversion function 2024-12-17 16:05:59 +08:00
4845520225 fix(range): fix missing explicit namespace qualification of Range::All() 2024-12-17 15:53:14 +08:00
68f0d19cac fix(*): fix the implementation of iterator functions such as operator++(int) 2024-12-17 15:51:35 +08:00
50b1d2bb29 fix(*): fix missing constexpr in some if constexpr 2024-12-17 15:49:46 +08:00
00be872d5c fix(range): fix DeclVal() usage in range library 2024-12-17 14:46:03 +08:00
312cfe4097 refactor(*): make type alias identifiers conform to the style for general type identifiers 2024-12-16 19:34:47 +08:00
d2b6e0c669 feat(range): add range pipe operator support 2024-12-16 15:09:57 +08:00
d88eb4be5e refactor(range): split the remaining range library into multiple files 2024-12-15 22:04:47 +08:00
dca4eaa6eb fix(range): fix related tool identifiers for common range 2024-12-15 16:20:04 +08:00
8eab5e6538 fix(iterator): fix requires on some iterator adapter member functions 2024-12-15 16:19:45 +08:00
589347118b refactor(range): split range factories part of the range library into multiple files 2024-12-15 11:55:02 +08:00
a3e0aa01cf refactor(range): split basic view part of the range library into multiple files 2024-12-15 11:24:30 +08:00
104 changed files with 13986 additions and 7582 deletions

View File

@ -46,7 +46,7 @@ public:
}; };
FMemoryLeakChecker MemoryLeakChecker; FMemoryLeakChecker GMemoryLeakChecker;
#endif #endif
@ -80,7 +80,7 @@ void* Malloc(size_t Count, size_t Alignment)
check(Result != nullptr); check(Result != nullptr);
check_code({ MemoryLeakChecker.AddMemoryAllocationCount(); }); check_code({ GMemoryLeakChecker.AddMemoryAllocationCount(); });
return Result; return Result;
} }
@ -139,7 +139,7 @@ void Free(void* Ptr)
} }
# endif # endif
check_code({ MemoryLeakChecker.ReleaseMemoryAllocationCount(); }); check_code({ GMemoryLeakChecker.ReleaseMemoryAllocationCount(); });
} }
size_t QuantizeSize(size_t Count, size_t Alignment) size_t QuantizeSize(size_t Count, size_t Alignment)

View 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

View 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)

View File

@ -1,4 +1,4 @@
#include "Numeric/Random.h" #include "Numerics/Random.h"
#include "Templates/Atomic.h" #include "Templates/Atomic.h"
@ -10,15 +10,15 @@ NAMESPACE_BEGIN(Math)
NAMESPACE_UNNAMED_BEGIN NAMESPACE_UNNAMED_BEGIN
TAtomic<uint32> RandState = 586103306; TAtomic<uint32> GRandState = 586103306;
NAMESPACE_UNNAMED_END NAMESPACE_UNNAMED_END
uint32 Seed(uint32 InSeed) uint32 Seed(uint32 InSeed)
{ {
uint32 OldSeed = RandState.Load(EMemoryOrder::Relaxed); uint32 OldSeed = GRandState.Load(EMemoryOrder::Relaxed);
if (InSeed != 0) RandState.Store(InSeed, EMemoryOrder::Relaxed); if (InSeed != 0) GRandState.Store(InSeed, EMemoryOrder::Relaxed);
return OldSeed; return OldSeed;
} }
@ -27,7 +27,7 @@ uint32 Rand()
{ {
uint32 Result; uint32 Result;
RandState.FetchFn( GRandState.FetchFn(
[&Result](uint32 Value) [&Result](uint32 Value)
{ {
Result = Value; Result = Value;

View 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

View File

@ -1,4 +1,4 @@
#include "Testing/ContainersTesting.h" #include "Testing/Testing.h"
#include "Containers/Containers.h" #include "Containers/Containers.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
@ -7,17 +7,11 @@ NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_MODULE_BEGIN(Utility)
// ReSharper disable CppInconsistentNaming
NAMESPACE_BEGIN(Testing) NAMESPACE_BEGIN(Testing)
void TestContainers() NAMESPACE_PRIVATE_BEGIN
{
TestArray();
TestStaticArray();
TestArrayView();
TestBitset();
TestStaticBitset();
TestList();
}
NAMESPACE_UNNAMED_BEGIN NAMESPACE_UNNAMED_BEGIN
@ -601,8 +595,22 @@ 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) NAMESPACE_END(Testing)
// ReSharper restore CppInconsistentNaming
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END

View 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

View File

@ -1,4 +1,4 @@
#include "Testing/MemoryTesting.h" #include "Testing/Testing.h"
#include "Memory/Memory.h" #include "Memory/Memory.h"
#include "Memory/Alignment.h" #include "Memory/Alignment.h"
@ -15,18 +15,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Testing) NAMESPACE_BEGIN(Testing)
void TestMemory() NAMESPACE_PRIVATE_BEGIN
{
TestAddress();
TestAlignment();
TestMemoryBuffer();
TestMemoryMalloc();
TestMemoryOperator();
TestPointerTraits();
TestUniquePointer();
TestSharedPointer();
TestInOutPointer();
}
NAMESPACE_UNNAMED_BEGIN NAMESPACE_UNNAMED_BEGIN
@ -255,23 +244,23 @@ void TestPointerTraits()
always_check(!TPointerTraits<int64>::bIsPointer); always_check(!TPointerTraits<int64>::bIsPointer);
always_check(TPointerTraits<int64*>::bIsPointer); always_check(TPointerTraits<int64*>::bIsPointer);
always_check((CSameAs<TPointerTraits<int64*>::PointerType, int64*>)); always_check((CSameAs<TPointerTraits<int64*>::FPointerType, int64*>));
always_check((CSameAs<TPointerTraits<int64*>::ElementType, int64>)); always_check((CSameAs<TPointerTraits<int64*>::FElementType, int64>));
always_check(TPointerTraits<int64*>::ToAddress(nullptr) == nullptr); always_check(TPointerTraits<int64*>::ToAddress(nullptr) == nullptr);
always_check(TPointerTraits<int64(*)[]>::bIsPointer); always_check(TPointerTraits<int64(*)[]>::bIsPointer);
always_check((CSameAs<TPointerTraits<int64(*)[]>::PointerType, int64(*)[]>)); always_check((CSameAs<TPointerTraits<int64(*)[]>::FPointerType, int64(*)[]>));
always_check((CSameAs<TPointerTraits<int64(*)[]>::ElementType, int64>)); always_check((CSameAs<TPointerTraits<int64(*)[]>::FElementType, int64>));
always_check(TPointerTraits<int64*>::ToAddress(nullptr) == nullptr); always_check(TPointerTraits<int64*>::ToAddress(nullptr) == nullptr);
always_check(TPointerTraits<TSharedPtr<int64>>::bIsPointer); always_check(TPointerTraits<TSharedPtr<int64>>::bIsPointer);
always_check((CSameAs<TPointerTraits<TSharedPtr<int64>>::PointerType, TSharedPtr<int64>>)); always_check((CSameAs<TPointerTraits<TSharedPtr<int64>>::FPointerType, TSharedPtr<int64>>));
always_check((CSameAs<TPointerTraits<TSharedPtr<int64>>::ElementType, int64>)); always_check((CSameAs<TPointerTraits<TSharedPtr<int64>>::FElementType, int64>));
always_check(TPointerTraits<TSharedPtr<int64>>::ToAddress(nullptr) == nullptr); always_check(TPointerTraits<TSharedPtr<int64>>::ToAddress(nullptr) == nullptr);
always_check(TPointerTraits<TSharedPtr<int64[]>>::bIsPointer); always_check(TPointerTraits<TSharedPtr<int64[]>>::bIsPointer);
always_check((CSameAs<TPointerTraits<TSharedPtr<int64[]>>::PointerType, TSharedPtr<int64[]>>)); always_check((CSameAs<TPointerTraits<TSharedPtr<int64[]>>::FPointerType, TSharedPtr<int64[]>>));
always_check((CSameAs<TPointerTraits<TSharedPtr<int64[]>>::ElementType, int64>)); always_check((CSameAs<TPointerTraits<TSharedPtr<int64[]>>::FElementType, int64>));
always_check(TPointerTraits<TSharedPtr<int64[]>>::ToAddress(nullptr) == nullptr); always_check(TPointerTraits<TSharedPtr<int64[]>>::ToAddress(nullptr) == nullptr);
} }
@ -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_END(Testing)
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)

View File

@ -1,4 +1,4 @@
#include "Testing/MiscellaneousTesting.h" #include "Testing/Testing.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
#include "Miscellaneous/Compare.h" #include "Miscellaneous/Compare.h"
@ -10,12 +10,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Testing) NAMESPACE_BEGIN(Testing)
void TestMiscellaneous() NAMESPACE_PRIVATE_BEGIN
{
TestAssertionMacros();
TestCompare();
TestVarArgs();
}
NAMESPACE_UNNAMED_BEGIN NAMESPACE_UNNAMED_BEGIN
@ -127,7 +122,7 @@ void TestCompare()
always_check(( 0 <=> 0) == strong_ordering::equivalent); always_check(( 0 <=> 0) == strong_ordering::equivalent);
always_check(( 0 <=> 0) == strong_ordering::equal); always_check(( 0 <=> 0) == strong_ordering::equal);
always_check(( 0 <=> -1) == strong_ordering::greater); always_check(( 0 <=> -1) == strong_ordering::greater);
always_check((-1 <=> 0) < 0); always_check((-1 <=> 0) < 0);
always_check((-1 <=> 0) <= 0); always_check((-1 <=> 0) <= 0);
always_check(( 0 <=> 0) <= 0); always_check(( 0 <=> 0) <= 0);
@ -148,12 +143,12 @@ void TestCompare()
always_check((-1.0 <=> 0.0) == weak_ordering::less); always_check((-1.0 <=> 0.0) == weak_ordering::less);
always_check(( 0.0 <=> 0.0) == weak_ordering::equivalent); always_check(( 0.0 <=> 0.0) == weak_ordering::equivalent);
always_check(( 0.0 <=> -1.0) == weak_ordering::greater); always_check(( 0.0 <=> -1.0) == weak_ordering::greater);
always_check((-1.0 <=> 0.0) == strong_ordering::less); 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::equivalent);
always_check(( 0.0 <=> 0.0) == strong_ordering::equal); always_check(( 0.0 <=> 0.0) == strong_ordering::equal);
always_check(( 0.0 <=> -1.0) == strong_ordering::greater); 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((-1.0 <=> 0.0) <= 0); always_check((-1.0 <=> 0.0) <= 0);
always_check(( 0.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(( 0.0 <=> -1.0) > 0); always_check(( 0.0 <=> -1.0) > 0);
always_check((-1.0 <=> 1.0) != 0); always_check((-1.0 <=> 1.0) != 0);
always_check((FTestPartialOrdering(-1) <=> FTestPartialOrdering( 0)) == partial_ordering::less); always_check((FTestPartialOrdering(-1) <=> FTestPartialOrdering( 0)) == partial_ordering::less);
always_check((FTestPartialOrdering( 0) <=> FTestPartialOrdering( 0)) == partial_ordering::equivalent); always_check((FTestPartialOrdering( 0) <=> FTestPartialOrdering( 0)) == partial_ordering::equivalent);
always_check((FTestPartialOrdering( 0) <=> FTestPartialOrdering(-1)) == partial_ordering::greater); always_check((FTestPartialOrdering( 0) <=> FTestPartialOrdering(-1)) == partial_ordering::greater);
always_check((FTestPartialOrdering( 0, true) <=> FTestPartialOrdering( 0, false)) == partial_ordering::unordered); always_check((FTestPartialOrdering( 0, true) <=> FTestPartialOrdering( 0, false)) == partial_ordering::unordered);
always_check((FTestWeakOrdering(-1) <=> FTestWeakOrdering( 0)) == weak_ordering::less); always_check((FTestWeakOrdering(-1) <=> FTestWeakOrdering( 0)) == weak_ordering::less);
always_check((FTestWeakOrdering( 0) <=> FTestWeakOrdering( 0)) == weak_ordering::equivalent); always_check((FTestWeakOrdering( 0) <=> FTestWeakOrdering( 0)) == weak_ordering::equivalent);
always_check((FTestWeakOrdering( 0) <=> FTestWeakOrdering(-1)) == weak_ordering::greater); always_check((FTestWeakOrdering( 0) <=> FTestWeakOrdering(-1)) == weak_ordering::greater);
always_check((FTestStrongOrdering(-1) <=> FTestStrongOrdering( 0)) == strong_ordering::less); 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::equivalent);
always_check((FTestStrongOrdering( 0) <=> FTestStrongOrdering( 0)) == strong_ordering::equal); always_check((FTestStrongOrdering( 0) <=> FTestStrongOrdering( 0)) == strong_ordering::equal);
always_check((FTestStrongOrdering( 0) <=> FTestStrongOrdering(-1)) == strong_ordering::greater); always_check((FTestStrongOrdering( 0) <=> FTestStrongOrdering(-1)) == strong_ordering::greater);
always_check((FTestPartialOrdering(-1) < FTestPartialOrdering( 0))); always_check((FTestPartialOrdering(-1) < FTestPartialOrdering( 0)));
always_check((FTestPartialOrdering( 0) == FTestPartialOrdering( 0))); always_check((FTestPartialOrdering( 0) == FTestPartialOrdering( 0)));
always_check((FTestPartialOrdering( 0) > FTestPartialOrdering(-1))); always_check((FTestPartialOrdering( 0) > FTestPartialOrdering(-1)));
always_check((FTestWeakOrdering(-1) < FTestWeakOrdering( 0))); always_check((FTestWeakOrdering(-1) < FTestWeakOrdering( 0)));
always_check((FTestWeakOrdering( 0) == FTestWeakOrdering( 0))); always_check((FTestWeakOrdering( 0) == FTestWeakOrdering( 0)));
always_check((FTestWeakOrdering( 0) > FTestWeakOrdering(-1))); 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), FTestPartialOrdering(-1)) == partial_ordering::greater);
always_check(SynthThreeWayCompare(FTestPartialOrdering( 0, true), FTestPartialOrdering( 0, false)) == partial_ordering::unordered); 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(-1), FTestSynth( 0)) == weak_ordering::less);
always_check(SynthThreeWayCompare(FTestSynth( 0), FTestSynth( 0)) == weak_ordering::equivalent); always_check(SynthThreeWayCompare(FTestSynth( 0), FTestSynth( 0)) == weak_ordering::equivalent);
always_check(SynthThreeWayCompare(FTestSynth( 0), FTestSynth(-1)) == weak_ordering::greater); 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_END(Testing)
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)

View File

@ -1,6 +1,6 @@
#include "Testing/NumericTesting.h" #include "Testing/Testing.h"
#include "Numeric/Numeric.h" #include "Numerics/Numerics.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
@ -9,12 +9,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Testing) NAMESPACE_BEGIN(Testing)
void TestNumeric() NAMESPACE_PRIVATE_BEGIN
{
TestLiteral();
TestBit();
TestMath();
}
void TestLiteral() void TestLiteral()
{ {
@ -606,6 +601,15 @@ void TestMath()
always_check(static_cast<uint8>(Math::LerpStable(0, 255, 1.0)) == 255); 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_END(Testing)
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)

View 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

View File

@ -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 "Memory/Memory.h"
#include "String/String.h" #include "Numerics/Numerics.h"
#include "Numeric/Numeric.h" #include "Strings/String.h"
#include "String/StringView.h" #include "Strings/StringView.h"
#include "Strings/Convert.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
@ -13,13 +14,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Testing) NAMESPACE_BEGIN(Testing)
void TestString() NAMESPACE_PRIVATE_BEGIN
{
TestChar();
TestStringView();
TestTemplateString();
TestStringConversion();
}
void TestChar() void TestChar()
{ {
@ -32,6 +27,7 @@ void TestChar()
always_check(CCharType<u32char>); always_check(CCharType<u32char>);
always_check(CCharType<unicodechar>); always_check(CCharType<unicodechar>);
} }
auto Test = []<typename T>(TInPlaceType<T>) auto Test = []<typename T>(TInPlaceType<T>)
{ {
always_check(TChar<T>::IsASCII(LITERAL(T, '0'))); 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, "012345678900").IsASCII());
always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").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, "012345678900").template IsInteger<uint64>(10));
always_check(!LITERAL_VIEW(T, "0123456789AB").IsInteger()); always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").template IsInteger<uint64>(10));
always_check( LITERAL_VIEW(T, "0123456789AB").IsInteger(16)); 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>); Test(InPlaceType<unicodechar>);
} }
void TestTemplateString() void TestString()
{ {
auto Test = []<typename T>(TInPlaceType<T>) auto Test = []<typename T>(TInPlaceType<T>)
{ {
@ -453,38 +450,17 @@ void TestTemplateString()
Test(InPlaceType<unicodechar>); Test(InPlaceType<unicodechar>);
} }
void TestStringConversion() void TestConvert()
{ {
auto Test = []<typename T>(TInPlaceType<T>) 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) auto CheckParseArithmetic = []<typename U>(TStringView<T> View, U Result)
{ {
U Object; U Object;
if constexpr (CSameAs<U, bool>) always_check(View.Parse(LITERAL(T, "{0:}"), Object) == 1); if constexpr (CSameAs<U, bool>) always_check(View.Parse(Object));
else if constexpr (CIntegral<U>) always_check(View.Parse(LITERAL(T, "{0:+#I}"), Object) == 1); else if constexpr (CIntegral<U>) always_check(View.Parse(Object));
else if constexpr (CFloatingPoint<U>) always_check(View.Parse(LITERAL(T, "{0:+#G}"), Object) == 1); else if constexpr (CFloatingPoint<U>) always_check(View.Parse(Object));
if constexpr (CFloatingPoint<U>) if constexpr (CFloatingPoint<U>)
{ {
@ -559,6 +535,68 @@ void TestStringConversion()
CheckParseFloat(InPlaceType<float>); CheckParseFloat(InPlaceType<float>);
CheckParseFloat(InPlaceType<double>); 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(true ) == LITERAL(T, "True" ));
always_check(TString<T>::FromBool(false) == LITERAL(T, "False")); 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(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(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>); Test(InPlaceType<char>);
@ -625,6 +632,17 @@ void TestStringConversion()
Test(InPlaceType<unicodechar>); 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_END(Testing)
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)

View File

@ -1,4 +1,4 @@
#include "Testing/TemplatesTesting.h" #include "Testing/Testing.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
#include "Miscellaneous/Compare.h" #include "Miscellaneous/Compare.h"
@ -14,20 +14,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Testing) NAMESPACE_BEGIN(Testing)
void TestTemplates() NAMESPACE_PRIVATE_BEGIN
{
TestInvoke();
TestReferenceWrapper();
TestOptional();
TestVariant();
TestAny();
TestTuple();
TestFunction();
TestAtomic();
TestScopeHelper();
TestPropagateConst();
TestMiscTemplates();
}
NAMESPACE_UNNAMED_BEGIN NAMESPACE_UNNAMED_BEGIN
@ -64,9 +51,9 @@ void TestInvoke()
void TestReferenceWrapper() void TestReferenceWrapper()
{ {
typedef int32(*FuncType)(int32, int32, int32); typedef int32(*FFuncType)(int32, int32, int32);
FuncType TempA = [](int32 A, int32 B, int32 C) -> int32 { return A * B * C; }; FFuncType TempA = [](int32 A, int32 B, int32 C) -> int32 { return A * B * C; };
TReferenceWrapper<FuncType> TempB(TempA); TReferenceWrapper<FFuncType> TempB(TempA);
always_check(TempB(1, 1, 1) == 1); always_check(TempB(1, 1, 1) == 1);
TempB.Get() = &TestFunctionA; TempB.Get() = &TestFunctionA;
always_check(TempA(1, 1, 1) == 3); always_check(TempA(1, 1, 1) == 3);
@ -330,14 +317,15 @@ void TestVariant()
} }
{ {
using VariantType = TVariant<int32, int64, float64>; using FVariantType = TVariant<int32, int64, float64>;
VariantType TempArray[] = { 10, 15ll, 1.5 }; FVariantType TempArray[] = { 10, 15ll, 1.5 };
for(auto&& TempA : TempArray) for(auto&& TempA : TempArray)
{ {
Visit( Visit(
[](auto&& A) [](auto&& A)
{ {
// ReSharper disable once CppInconsistentNaming
using T = TRemoveCVRef<decltype(A)>; using T = TRemoveCVRef<decltype(A)>;
if constexpr (CSameAs<T, int32>) always_check(A == 10); if constexpr (CSameAs<T, int32>) always_check(A == 10);
else if constexpr (CSameAs<T, int64>) always_check(A == 15ll); else if constexpr (CSameAs<T, int64>) always_check(A == 15ll);
@ -347,11 +335,12 @@ void TestVariant()
TempA TempA
); );
VariantType TempB = Visit([](auto&& A) -> VariantType { return A + A; }, TempA); FVariantType TempB = Visit([](auto&& A) -> FVariantType { return A + A; }, TempA);
Visit( Visit(
[](auto&& A, auto&& B) [](auto&& A, auto&& B)
{ {
// ReSharper disable once CppInconsistentNaming
using T = TRemoveCVRef<decltype(A)>; using T = TRemoveCVRef<decltype(A)>;
if constexpr (CSameAs<T, int32>) always_check(A == 10 && B == 20); if constexpr (CSameAs<T, int32>) always_check(A == 10 && B == 20);
else if constexpr (CSameAs<T, int64>) always_check(A == 15ll && B == 30ll); else if constexpr (CSameAs<T, int64>) always_check(A == 15ll && B == 30ll);
@ -366,6 +355,7 @@ void TestVariant()
Visit( Visit(
[](auto&& A) [](auto&& A)
{ {
// ReSharper disable once CppInconsistentNaming
using T = TRemoveCVRef<decltype(A)>; using T = TRemoveCVRef<decltype(A)>;
if constexpr (CSameAs<T, int32>) always_check(A == 20); if constexpr (CSameAs<T, int32>) always_check(A == 20);
else if constexpr (CSameAs<T, int64>) always_check(A == 30ll); else if constexpr (CSameAs<T, int64>) always_check(A == 30ll);
@ -417,6 +407,7 @@ void TestVariant()
auto TestQualifiers = [&bIsConst, &bIsLValue, &bIsRValue](auto&& A) -> int32 auto TestQualifiers = [&bIsConst, &bIsLValue, &bIsRValue](auto&& A) -> int32
{ {
// ReSharper disable once CppInconsistentNaming
using T = decltype(A); using T = decltype(A);
always_check(A == 10); always_check(A == 10);
always_check(CConst<TRemoveReference<T>> == bIsConst); always_check(CConst<TRemoveReference<T>> == bIsConst);
@ -429,6 +420,8 @@ void TestVariant()
bIsLValue = true; bIsLValue = true;
bIsRValue = false; bIsRValue = false;
// ReSharper disable CppInconsistentNaming
TVariant<int32> TempLA = 10; TVariant<int32> TempLA = 10;
auto ReturnLA = Visit(TestQualifiers, TempLA); auto ReturnLA = Visit(TestQualifiers, TempLA);
always_check((CSameAs<int32, decltype(ReturnLA)>)); always_check((CSameAs<int32, decltype(ReturnLA)>));
@ -488,6 +481,8 @@ void TestVariant()
const TVariant<int32> TempRD = TempLC; const TVariant<int32> TempRD = TempLC;
auto ReturnRD = Visit<int32>(TestQualifiers, MoveTemp(TempRD)); auto ReturnRD = Visit<int32>(TestQualifiers, MoveTemp(TempRD));
always_check((CSameAs<int32, decltype(ReturnRD)>)); always_check((CSameAs<int32, decltype(ReturnRD)>));
// ReSharper restore CppInconsistentNaming
} }
{ {
@ -869,11 +864,11 @@ void TestTuple()
// always_check((CSameAs<TTupleElement<4, TTuple<double, float&, char&&>>, double>)); // always_check((CSameAs<TTupleElement<4, TTuple<double, float&, char&&>>, double>));
{ {
using Type = TTuple<int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64, using FType = TTuple<int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64,
int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64,
int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64>; int8, uint8, int16, uint16, int32, uint32, int64, uint64, int8, uint8, int16, uint16, int32, uint32, int64, uint64>;
Type Temp; FType Temp;
Temp.First = 0; Temp.First = 0;
Temp.Second = 0; Temp.Second = 0;
@ -892,20 +887,20 @@ void TestTuple()
Temp.Fifteenth = 0; Temp.Fifteenth = 0;
Temp.Sixteenth = 0; Temp.Sixteenth = 0;
always_check(CDefaultConstructible<Type>); always_check(CDefaultConstructible<FType>);
always_check(CTriviallyDefaultConstructible<Type>); always_check(CTriviallyDefaultConstructible<FType>);
always_check(CConstructibleFrom<Type>); always_check(CConstructibleFrom<FType>);
always_check(CTriviallyConstructibleFrom<Type>); always_check(CTriviallyConstructibleFrom<FType>);
always_check(CCopyConstructible<Type>); always_check(CCopyConstructible<FType>);
always_check(CTriviallyCopyConstructible<Type>); always_check(CTriviallyCopyConstructible<FType>);
always_check(CMoveConstructible<Type>); always_check(CMoveConstructible<FType>);
always_check(CTriviallyMoveConstructible<Type>); always_check(CTriviallyMoveConstructible<FType>);
always_check(CCopyAssignable<Type>); always_check(CCopyAssignable<FType>);
always_check(CTriviallyCopyAssignable<Type>); always_check(CTriviallyCopyAssignable<FType>);
always_check(CMoveAssignable<Type>); always_check(CMoveAssignable<FType>);
always_check(CTriviallyMoveAssignable<Type>); always_check(CTriviallyMoveAssignable<FType>);
always_check(CDestructible<Type>); always_check(CDestructible<FType>);
always_check(CTriviallyDestructible<Type>); always_check(CTriviallyDestructible<FType>);
} }
{ {
@ -1006,13 +1001,13 @@ void TestTuple()
{ {
TTuple<int32, char> TempA = { 1, 'A' }; TTuple<int32, char> TempA = { 1, 'A' };
TempA.Visit([](auto&& A) { A++; }); TempA.Visit([](auto&& A) -> void { ++A; });
TempA.Visit( TempA.Visit(
[]<typename T> (T&& A) []<typename T> (T&& A)
{ {
if constexpr (CSameAs<T&&, int32&>) always_check(A == 2); if constexpr (CSameAs<T&&, int32&>) always_check(A == 2 );
else if constexpr (CSameAs<T&&, char&>) always_check(A == 'B'); else if constexpr (CSameAs<T&&, char &>) always_check(A == 'B');
else always_check_no_entry(); else always_check_no_entry();
} }
); );
@ -1084,25 +1079,25 @@ struct FFunctionDebug
void Print(int32 In) { Output[Index++] = In; } void Print(int32 In) { Output[Index++] = In; }
}; };
FFunctionDebug FunctionDebug; FFunctionDebug GFunctionDebug;
struct FPrintAdd struct FPrintAdd
{ {
FPrintAdd(int32 InNum) : Num(InNum) { } FPrintAdd(int32 InNum) : Num(InNum) { }
void F(int32 I) const { FunctionDebug.Print(Num + I); } void F(int32 I) const { GFunctionDebug.Print(Num + I); }
int32 Num; int32 Num;
}; };
void PrintNum(int32 I) void PrintNum(int32 I)
{ {
FunctionDebug.Print(I); GFunctionDebug.Print(I);
} }
struct FPrintNum struct FPrintNum
{ {
void operator()(int32 I) const void operator()(int32 I) const
{ {
FunctionDebug.Print(I); GFunctionDebug.Print(I);
} }
}; };
@ -1310,7 +1305,7 @@ void TestFunction()
AddDisplay(314159, 1); AddDisplay(314159, 1);
TFunction<int32(FPrintAdd const&)> Num = &FPrintAdd::Num; TFunction<int32(FPrintAdd const&)> Num = &FPrintAdd::Num;
FunctionDebug.Print(Num(Foo)); GFunctionDebug.Print(Num(Foo));
TFunction<void(int32)> AddDisplay2 = [Foo](int32 A) { Foo.F(A); }; TFunction<void(int32)> AddDisplay2 = [Foo](int32 A) { Foo.F(A); };
AddDisplay2(2); AddDisplay2(2);
@ -1326,21 +1321,21 @@ void TestFunction()
return Fac(N); return Fac(N);
}; };
for (int32 I = 5; I < 8; ++I) FunctionDebug.Print(Factorial(I)); for (int32 I = 5; I < 8; ++I) GFunctionDebug.Print(Factorial(I));
always_check(FunctionDebug.Index == 12); always_check(GFunctionDebug.Index == 12);
always_check(FunctionDebug.Output[0] == -9); always_check(GFunctionDebug.Output[0] == -9);
always_check(FunctionDebug.Output[1] == 42); always_check(GFunctionDebug.Output[1] == 42);
always_check(FunctionDebug.Output[2] == 31337); always_check(GFunctionDebug.Output[2] == 31337);
always_check(FunctionDebug.Output[3] == 314160); always_check(GFunctionDebug.Output[3] == 314160);
always_check(FunctionDebug.Output[4] == 314160); always_check(GFunctionDebug.Output[4] == 314160);
always_check(FunctionDebug.Output[5] == 314159); always_check(GFunctionDebug.Output[5] == 314159);
always_check(FunctionDebug.Output[6] == 314161); always_check(GFunctionDebug.Output[6] == 314161);
always_check(FunctionDebug.Output[7] == 314162); always_check(GFunctionDebug.Output[7] == 314162);
always_check(FunctionDebug.Output[8] == 18); always_check(GFunctionDebug.Output[8] == 18);
always_check(FunctionDebug.Output[9] == 120); always_check(GFunctionDebug.Output[9] == 120);
always_check(FunctionDebug.Output[10] == 720); always_check(GFunctionDebug.Output[10] == 720);
always_check(FunctionDebug.Output[11] == 5040); always_check(GFunctionDebug.Output[11] == 5040);
} }
{ {
@ -1613,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_END(Testing)
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)

View File

@ -1,4 +1,4 @@
#include "Testing/TypeTraitsTesting.h" #include "Testing/Testing.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
@ -14,7 +14,7 @@ NAMESPACE_BEGIN(Testing)
NAMESPACE_UNNAMED_BEGIN NAMESPACE_UNNAMED_BEGIN
int32 TestObject; int32 GTestObject;
void TestFunction() { } void TestFunction() { }
struct FTestStructA { }; struct FTestStructA { };
@ -89,7 +89,7 @@ void TestTypeTraits()
always_check(!CLValueReference<int32>); always_check(!CLValueReference<int32>);
always_check(CLValueReference<int32&>); always_check(CLValueReference<int32&>);
always_check(!CLValueReference<int32&&>); always_check(!CLValueReference<int32&&>);
always_check(!CRValueReference<int32>); always_check(!CRValueReference<int32>);
always_check(!CRValueReference<int32&>); always_check(!CRValueReference<int32&>);
always_check(CRValueReference<int32&&>); always_check(CRValueReference<int32&&>);
@ -428,9 +428,9 @@ void TestTypeTraits()
always_check((CSameAs<void, TVoid<int32>>)); always_check((CSameAs<void, TVoid<int32>>));
always_check((CSameAs<void, TVoid<int32, int64>>)); always_check((CSameAs<void, TVoid<int32, int64>>));
// Invocable.h // Invocable.h
always_check((CInvocable<int32()>)); always_check((CInvocable<int32()>));
always_check((CInvocable<int32(int32), int32>)); always_check((CInvocable<int32(int32), int32>));
always_check(!(CInvocable<int32(int32), FTestStructA>)); always_check(!(CInvocable<int32(int32), FTestStructA>));
@ -462,7 +462,7 @@ void TestTypeTraits()
always_check((CSameAs<int32, TCommonReference<int8, int32>>)); always_check((CSameAs<int32, TCommonReference<int8, int32>>));
always_check((CSameAs<int64, TCommonReference<int8, int32, int64>>)); always_check((CSameAs<int64, TCommonReference<int8, int32, int64>>));
always_check((CSameAs<double, TCommonReference<float, double>>)); always_check((CSameAs<double, TCommonReference<float, double>>));
always_check((CCommonType<int32, int32>)); always_check((CCommonType<int32, int32>));
always_check((CCommonType<int8, int32>)); always_check((CCommonType<int8, int32>));
always_check((CCommonType<float, double>)); always_check((CCommonType<float, double>));
@ -493,7 +493,7 @@ void TestTypeTraits()
always_check((CSameAs<const volatile int32, TCopyConst< int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyConst< int32, const volatile int32>>));
always_check((CSameAs<const volatile int32, TCopyConst<const int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyConst<const int32, const volatile int32>>));
always_check((CSameAs<const volatile int32, TCopyConst<const volatile int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyConst<const volatile int32, const volatile int32>>));
always_check((CSameAs< int32, TCopyVolatile< int32, int32>>)); always_check((CSameAs< int32, TCopyVolatile< int32, int32>>));
always_check((CSameAs< int32, TCopyVolatile<const int32, int32>>)); always_check((CSameAs< int32, TCopyVolatile<const int32, int32>>));
always_check((CSameAs< volatile int32, TCopyVolatile<const volatile int32, int32>>)); always_check((CSameAs< volatile int32, TCopyVolatile<const volatile int32, int32>>));
@ -503,7 +503,7 @@ void TestTypeTraits()
always_check((CSameAs<const volatile int32, TCopyVolatile< int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyVolatile< int32, const volatile int32>>));
always_check((CSameAs<const volatile int32, TCopyVolatile<const int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyVolatile<const int32, const volatile int32>>));
always_check((CSameAs<const volatile int32, TCopyVolatile<const volatile int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyVolatile<const volatile int32, const volatile int32>>));
always_check((CSameAs< int32, TCopyCV< int32, int32>>)); always_check((CSameAs< int32, TCopyCV< int32, int32>>));
always_check((CSameAs<const int32, TCopyCV<const int32, int32>>)); always_check((CSameAs<const int32, TCopyCV<const int32, int32>>));
always_check((CSameAs<const volatile int32, TCopyCV<const volatile int32, int32>>)); always_check((CSameAs<const volatile int32, TCopyCV<const volatile int32, int32>>));
@ -513,7 +513,7 @@ void TestTypeTraits()
always_check((CSameAs<const volatile int32, TCopyCV< int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyCV< int32, const volatile int32>>));
always_check((CSameAs<const volatile int32, TCopyCV<const int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyCV<const int32, const volatile int32>>));
always_check((CSameAs<const volatile int32, TCopyCV<const volatile int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyCV<const volatile int32, const volatile int32>>));
always_check((CSameAs<int32, TCopyReference<int32, int32 >>)); always_check((CSameAs<int32, TCopyReference<int32, int32 >>));
always_check((CSameAs<int32&, TCopyReference<int32, int32& >>)); always_check((CSameAs<int32&, TCopyReference<int32, int32& >>));
always_check((CSameAs<int32&&, TCopyReference<int32, int32&&>>)); always_check((CSameAs<int32&&, TCopyReference<int32, int32&&>>));
@ -539,7 +539,7 @@ void TestTypeTraits()
always_check((CSameAs<const volatile int32, TCopyCVRef< int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyCVRef< int32, const volatile int32>>));
always_check((CSameAs<const volatile int32, TCopyCVRef<const int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyCVRef<const int32, const volatile int32>>));
always_check((CSameAs<const volatile int32, TCopyCVRef<const volatile int32, const volatile int32>>)); always_check((CSameAs<const volatile int32, TCopyCVRef<const volatile int32, const volatile int32>>));
always_check((CSameAs<int32, TCopyCVRef<int32, int32 >>)); always_check((CSameAs<int32, TCopyCVRef<int32, int32 >>));
always_check((CSameAs<int32&, TCopyCVRef<int32, int32& >>)); always_check((CSameAs<int32&, TCopyCVRef<int32, int32& >>));
always_check((CSameAs<int32&&, TCopyCVRef<int32, int32&&>>)); always_check((CSameAs<int32&&, TCopyCVRef<int32, int32&&>>));

View File

@ -0,0 +1,5 @@
#pragma once
#include "CoreTypes.h"
#include "Algorithms/Basic.h"
#include "Algorithms/Search.h"

View 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

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,19 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Memory/Allocator.h" #include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "Templates/TypeHash.h" #include "Templates/TypeHash.h"
#include "TypeTraits/TypeTraits.h" #include "Memory/Allocators.h"
#include "Miscellaneous/Compare.h"
#include "Memory/MemoryOperator.h" #include "Memory/MemoryOperator.h"
#include "Miscellaneous/Iterator.h" #include "Iterators/Utility.h"
#include "Miscellaneous/Container.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" #include "Miscellaneous/AssertionMacros.h"
#include "Miscellaneous/ConstantIterator.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Redcraft)
@ -27,48 +30,54 @@ private:
public: public:
using ElementType = T; using FElementType = T;
using AllocatorType = Allocator; using FAllocatorType = Allocator;
using Reference = T&; using FReference = T&;
using ConstReference = const T&; using FConstReference = const T&;
using Iterator = TIteratorImpl<false>; using FIterator = TIteratorImpl<false>;
using ConstIterator = TIteratorImpl<true >; using FConstIterator = TIteratorImpl<true >;
using ReverseIterator = TReverseIterator< Iterator>; using FReverseIterator = TReverseIterator< FIterator>;
using ConstReverseIterator = TReverseIterator<ConstIterator>; using FConstReverseIterator = TReverseIterator<FConstIterator>;
static_assert(CContiguousIterator< Iterator>); static_assert(CContiguousIterator< FIterator>);
static_assert(CContiguousIterator<ConstIterator>); static_assert(CContiguousIterator<FConstIterator>);
/** Default constructor. Constructs an empty container with a default-constructed allocator. */ /** Default constructor. Constructs an empty container with a default-constructed allocator. */
FORCEINLINE TArray() : TArray(0) { } FORCEINLINE TArray() : TArray(0) { }
/** Constructs the container with 'Count' default instances of T. */ /** Constructs the container with 'Count' default instances of T. */
explicit TArray(size_t Count) requires (CDefaultConstructible<ElementType>) explicit TArray(size_t Count) requires (CDefaultConstructible<T>)
{ {
Impl.ArrayNum = Count; Impl.ArrayNum = Count;
Impl.ArrayMax = Impl->CalculateSlackReserve(Num()); Impl.ArrayMax = Impl->CalculateSlackReserve(Num());
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::DefaultConstruct<ElementType>(Impl.Pointer, Num()); Memory::DefaultConstruct<FElementType>(Impl.Pointer, Num());
} }
/** Constructs the container with 'Count' copies of elements with 'InValue'. */ /** Constructs the container with 'Count' copies of elements with 'InValue'. */
TArray(size_t Count, const ElementType& InValue) requires (CCopyConstructible<ElementType>) FORCEINLINE explicit TArray(size_t Count, const FElementType& InValue) requires (CCopyConstructible<T>)
: TArray(MakeCountedConstantIterator(InValue, Count), DefaultSentinel) : TArray(Ranges::Repeat(InValue, Count))
{ } { }
/** Constructs the container with the contents of the range ['First', 'Last'). */ /** Constructs the container with the contents of the range ['First', 'Last'). */
template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<ElementType, TIteratorReferenceType<I>> && CMovable<ElementType>) template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<T, TIteratorReference<I>> && CMovable<T>)
TArray(I First, S Last) explicit TArray(I First, S Last)
{ {
if constexpr (CForwardIterator<I>) if constexpr (CForwardIterator<I>)
{ {
if (CSizedSentinelFor<S, I>) { checkf(First <= Last, TEXT("Illegal range iterator. Please check First <= Last.")); } size_t Count = 0;
const size_t Count = Iteration::Distance(First, Last); if constexpr (CSizedSentinelFor<S, I>)
{
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
Count = Last - First;
}
else for (I Iter = First; Iter != Last; ++Iter) ++Count;
Impl.ArrayNum = Count; Impl.ArrayNum = Count;
Impl.ArrayMax = Impl->CalculateSlackReserve(Num()); Impl.ArrayMax = Impl->CalculateSlackReserve(Num());
@ -76,7 +85,7 @@ public:
for (size_t Index = 0; Index != Count; ++Index) for (size_t Index = 0; Index != Count; ++Index)
{ {
new (Impl.Pointer + Index) ElementType(*First++); new (Impl.Pointer + Index) FElementType(*First++);
} }
} }
else else
@ -93,18 +102,22 @@ 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(Ranges::Begin(Range), Ranges::End(Range)) { }
/** Copy constructor. Constructs the container with the copy of the contents of 'InValue'. */ /** Copy constructor. Constructs the container with the copy of the contents of 'InValue'. */
TArray(const TArray& InValue) requires (CCopyConstructible<ElementType>) TArray(const TArray& InValue) requires (CCopyConstructible<T>)
{ {
Impl.ArrayNum = InValue.Num(); Impl.ArrayNum = InValue.Num();
Impl.ArrayMax = Impl->CalculateSlackReserve(Num()); Impl.ArrayMax = Impl->CalculateSlackReserve(Num());
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::CopyConstruct<ElementType>(Impl.Pointer, InValue.Impl.Pointer, Num()); Memory::CopyConstruct<FElementType>(Impl.Pointer, InValue.Impl.Pointer, Num());
} }
/** Move constructor. After the move, 'InValue' is guaranteed to be empty. */ /** Move constructor. After the move, 'InValue' is guaranteed to be empty. */
TArray(TArray&& InValue) requires (CMoveConstructible<ElementType>) TArray(TArray&& InValue) requires (CMoveConstructible<T>)
{ {
Impl.ArrayNum = InValue.Num(); Impl.ArrayNum = InValue.Num();
@ -122,14 +135,14 @@ public:
Impl.ArrayMax = Impl->CalculateSlackReserve(Num()); Impl.ArrayMax = Impl->CalculateSlackReserve(Num());
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, InValue.Impl.Pointer, Num()); Memory::MoveConstruct<FElementType>(Impl.Pointer, InValue.Impl.Pointer, Num());
} }
InValue.Reset(); InValue.Reset();
} }
/** Constructs the container with the contents of the initializer list. */ /** Constructs the container with the contents of the initializer list. */
FORCEINLINE TArray(initializer_list<ElementType> IL) requires (CCopyConstructible<ElementType>) : TArray(Iteration::Begin(IL), Iteration::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. */ /** Destructs the array. The destructors of the elements are called and the used storage is deallocated. */
~TArray() ~TArray()
@ -139,7 +152,7 @@ public:
} }
/** Copy assignment operator. Replaces the contents with a copy of the contents of 'InValue'. */ /** Copy assignment operator. Replaces the contents with a copy of the contents of 'InValue'. */
TArray& operator=(const TArray& InValue) requires (CCopyable<ElementType>) TArray& operator=(const TArray& InValue) requires (CCopyable<T>)
{ {
if (&InValue == this) UNLIKELY return *this; if (&InValue == this) UNLIKELY return *this;
@ -157,7 +170,7 @@ public:
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::CopyConstruct<ElementType>(Impl.Pointer, InValue.Impl.Pointer, Num()); Memory::CopyConstruct<FElementType>(Impl.Pointer, InValue.Impl.Pointer, Num());
return *this; return *this;
} }
@ -170,7 +183,7 @@ public:
else if (InValue.Num() <= Max()) else if (InValue.Num() <= Max())
{ {
Memory::CopyAssign(Impl.Pointer, InValue.Impl.Pointer, Num()); Memory::CopyAssign(Impl.Pointer, InValue.Impl.Pointer, Num());
Memory::CopyConstruct<ElementType>(Impl.Pointer + Num(), InValue.Impl.Pointer + Num(), InValue.Num() - Num()); Memory::CopyConstruct<FElementType>(Impl.Pointer + Num(), InValue.Impl.Pointer + Num(), InValue.Num() - Num());
} }
else check_no_entry(); else check_no_entry();
@ -180,7 +193,7 @@ public:
} }
/** Move assignment operator. After the move, 'InValue' is guaranteed to be empty. */ /** Move assignment operator. After the move, 'InValue' is guaranteed to be empty. */
TArray& operator=(TArray&& InValue) requires (CMovable<ElementType>) TArray& operator=(TArray&& InValue) requires (CMovable<T>)
{ {
if (&InValue == this) UNLIKELY return *this; if (&InValue == this) UNLIKELY return *this;
@ -214,7 +227,7 @@ public:
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, InValue.Impl.Pointer, Num()); Memory::MoveConstruct<FElementType>(Impl.Pointer, InValue.Impl.Pointer, Num());
InValue.Reset(); InValue.Reset();
@ -229,7 +242,7 @@ public:
else if (InValue.Num() <= Max()) else if (InValue.Num() <= Max())
{ {
Memory::MoveAssign(Impl.Pointer, InValue.Impl.Pointer, Num()); Memory::MoveAssign(Impl.Pointer, InValue.Impl.Pointer, Num());
Memory::MoveConstruct<ElementType>(Impl.Pointer + Num(), InValue.Impl.Pointer + Num(), InValue.Num() - Num()); Memory::MoveConstruct<FElementType>(Impl.Pointer + Num(), InValue.Impl.Pointer + Num(), InValue.Num() - Num());
} }
else check_no_entry(); else check_no_entry();
@ -241,46 +254,46 @@ public:
} }
/** Replaces the contents with those identified by initializer list. */ /** Replaces the contents with those identified by initializer list. */
TArray& operator=(initializer_list<ElementType> IL) requires (CCopyable<ElementType>) TArray& operator=(initializer_list<FElementType> IL) requires (CCopyable<T>)
{ {
size_t NumToAllocate = GetNum(IL); size_t NumToAllocate = Ranges::Num(IL);
NumToAllocate = NumToAllocate > Max() ? Impl->CalculateSlackGrow(GetNum(IL), Max()) : NumToAllocate; NumToAllocate = NumToAllocate > Max() ? Impl->CalculateSlackGrow (Ranges::Num(IL), Max()) : NumToAllocate;
NumToAllocate = NumToAllocate < Max() ? Impl->CalculateSlackShrink(GetNum(IL), Max()) : NumToAllocate; NumToAllocate = NumToAllocate < Max() ? Impl->CalculateSlackShrink(Ranges::Num(IL), Max()) : NumToAllocate;
if (NumToAllocate != Max()) if (NumToAllocate != Max())
{ {
Memory::Destruct(Impl.Pointer, Num()); Memory::Destruct(Impl.Pointer, Num());
Impl->Deallocate(Impl.Pointer); Impl->Deallocate(Impl.Pointer);
Impl.ArrayNum = GetNum(IL); Impl.ArrayNum = Ranges::Num(IL);
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::CopyConstruct<ElementType>(Impl.Pointer, NAMESPACE_REDCRAFT::GetData(IL), Num()); Memory::CopyConstruct<FElementType>(Impl.Pointer, Ranges::GetData(IL), Num());
return *this; return *this;
} }
if (GetNum(IL) <= Num()) if (Ranges::Num(IL) <= Num())
{ {
Memory::CopyAssign(Impl.Pointer, NAMESPACE_REDCRAFT::GetData(IL), GetNum(IL)); Memory::CopyAssign(Impl.Pointer, Ranges::GetData(IL), Ranges::Num(IL));
Memory::Destruct(Impl.Pointer + GetNum(IL), Num() - GetNum(IL)); Memory::Destruct(Impl.Pointer + Ranges::Num(IL), Num() - Ranges::Num(IL));
} }
else if (GetNum(IL) <= Max()) else if (Ranges::Num(IL) <= Max())
{ {
Memory::CopyAssign(Impl.Pointer, NAMESPACE_REDCRAFT::GetData(IL), Num()); Memory::CopyAssign(Impl.Pointer, Ranges::GetData(IL), Num());
Memory::CopyConstruct<ElementType>(Impl.Pointer + Num(), NAMESPACE_REDCRAFT::GetData(IL) + Num(), GetNum(IL) - Num()); Memory::CopyConstruct<FElementType>(Impl.Pointer + Num(), Ranges::GetData(IL) + Num(), Ranges::Num(IL) - Num());
} }
else check_no_entry(); else check_no_entry();
Impl.ArrayNum = GetNum(IL); Impl.ArrayNum = Ranges::Num(IL);
return *this; return *this;
} }
/** Compares the contents of two arrays. */ /** Compares the contents of two arrays. */
NODISCARD friend bool operator==(const TArray& LHS, const TArray& RHS) requires (CWeaklyEqualityComparable<ElementType>) NODISCARD friend bool operator==(const TArray& LHS, const TArray& RHS) requires (CWeaklyEqualityComparable<T>)
{ {
if (LHS.Num() != RHS.Num()) return false; if (LHS.Num() != RHS.Num()) return false;
@ -293,7 +306,7 @@ public:
} }
/** Compares the contents of 'LHS' and 'RHS' lexicographically. */ /** Compares the contents of 'LHS' and 'RHS' lexicographically. */
NODISCARD friend auto operator<=>(const TArray& LHS, const TArray& RHS) requires (CSynthThreeWayComparable<ElementType>) NODISCARD friend auto operator<=>(const TArray& LHS, const TArray& RHS) requires (CSynthThreeWayComparable<T>)
{ {
const size_t NumToCompare = LHS.Num() < RHS.Num() ? LHS.Num() : RHS.Num(); const size_t NumToCompare = LHS.Num() < RHS.Num() ? LHS.Num() : RHS.Num();
@ -306,7 +319,7 @@ public:
} }
/** Inserts 'InValue' before 'Iter' in the container. */ /** Inserts 'InValue' before 'Iter' in the container. */
Iterator Insert(ConstIterator Iter, const ElementType& InValue) requires (CCopyable<ElementType>) FIterator Insert(FConstIterator Iter, const FElementType& InValue) requires (CCopyable<T>)
{ {
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator()."));
@ -318,26 +331,26 @@ public:
if (NumToAllocate != Max()) if (NumToAllocate != Max())
{ {
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = Num(); const size_t NumToDestruct = Num();
Impl.ArrayNum = Num() + 1; Impl.ArrayNum = Num() + 1;
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, InsertIndex); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, InsertIndex);
new (Impl.Pointer + InsertIndex) ElementType(InValue); new (Impl.Pointer + InsertIndex) FElementType(InValue);
Memory::MoveConstruct<ElementType>(Impl.Pointer + InsertIndex + 1, OldAllocation + InsertIndex, NumToDestruct - InsertIndex); Memory::MoveConstruct<FElementType>(Impl.Pointer + InsertIndex + 1, OldAllocation + InsertIndex, NumToDestruct - InsertIndex);
Memory::Destruct(OldAllocation, NumToDestruct); Memory::Destruct(OldAllocation, NumToDestruct);
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
return Iterator(this, Impl.Pointer + InsertIndex); return FIterator(this, Impl.Pointer + InsertIndex);
} }
if (InsertIndex != Num()) if (InsertIndex != Num())
{ {
new (Impl.Pointer + Num()) ElementType(MoveTemp(Impl.Pointer[Num() - 1])); new (Impl.Pointer + Num()) FElementType(MoveTemp(Impl.Pointer[Num() - 1]));
for (size_t Index = Num() - 1; Index != InsertIndex; --Index) for (size_t Index = Num() - 1; Index != InsertIndex; --Index)
{ {
@ -346,15 +359,15 @@ public:
Impl.Pointer[InsertIndex] = InValue; Impl.Pointer[InsertIndex] = InValue;
} }
else new (Impl.Pointer + Num()) ElementType(InValue); else new (Impl.Pointer + Num()) FElementType(InValue);
Impl.ArrayNum = Num() + 1; Impl.ArrayNum = Num() + 1;
return Iterator(this, Impl.Pointer + InsertIndex); return FIterator(this, Impl.Pointer + InsertIndex);
} }
/** Inserts 'InValue' before 'Iter' in the container. */ /** Inserts 'InValue' before 'Iter' in the container. */
Iterator Insert(ConstIterator Iter, ElementType&& InValue) requires (CMovable<ElementType>) FIterator Insert(FConstIterator Iter, FElementType&& InValue) requires (CMovable<T>)
{ {
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator()."));
@ -366,26 +379,26 @@ public:
if (NumToAllocate != Max()) if (NumToAllocate != Max())
{ {
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = Num(); const size_t NumToDestruct = Num();
Impl.ArrayNum = Num() + 1; Impl.ArrayNum = Num() + 1;
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, InsertIndex); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, InsertIndex);
new (Impl.Pointer + InsertIndex) ElementType(MoveTemp(InValue)); new (Impl.Pointer + InsertIndex) FElementType(MoveTemp(InValue));
Memory::MoveConstruct<ElementType>(Impl.Pointer + InsertIndex + 1, OldAllocation + InsertIndex, NumToDestruct - InsertIndex); Memory::MoveConstruct<FElementType>(Impl.Pointer + InsertIndex + 1, OldAllocation + InsertIndex, NumToDestruct - InsertIndex);
Memory::Destruct(OldAllocation, NumToDestruct); Memory::Destruct(OldAllocation, NumToDestruct);
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
return Iterator(this, Impl.Pointer + InsertIndex); return FIterator(this, Impl.Pointer + InsertIndex);
} }
if (InsertIndex != Num()) if (InsertIndex != Num())
{ {
new (Impl.Pointer + Num()) ElementType(MoveTemp(Impl.Pointer[Num() - 1])); new (Impl.Pointer + Num()) FElementType(MoveTemp(Impl.Pointer[Num() - 1]));
for (size_t Index = Num() - 1; Index != InsertIndex; --Index) for (size_t Index = Num() - 1; Index != InsertIndex; --Index)
{ {
@ -394,36 +407,42 @@ public:
Impl.Pointer[InsertIndex] = MoveTemp(InValue); Impl.Pointer[InsertIndex] = MoveTemp(InValue);
} }
else new (Impl.Pointer + Num()) ElementType(MoveTemp(InValue)); else new (Impl.Pointer + Num()) FElementType(MoveTemp(InValue));
Impl.ArrayNum = Num() + 1; Impl.ArrayNum = Num() + 1;
return Iterator(this, Impl.Pointer + InsertIndex); return FIterator(this, Impl.Pointer + InsertIndex);
} }
/** Inserts 'Count' copies of the 'InValue' before 'Iter' in the container. */ /** Inserts 'Count' copies of the 'InValue' before 'Iter' in the container. */
Iterator Insert(ConstIterator Iter, size_t Count, const ElementType& InValue) requires (CCopyable<ElementType>) FIterator Insert(FConstIterator Iter, size_t Count, const FElementType& InValue) requires (CCopyable<T>)
{ {
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator()."));
return Insert(Iter, MakeCountedConstantIterator(InValue, Count), DefaultSentinel); return Insert(Iter, Ranges::Repeat(InValue, Count));
} }
/** Inserts elements from range ['First', 'Last') before 'Iter'. */ /** Inserts elements from range ['First', 'Last') before 'Iter'. */
template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<ElementType, TIteratorReferenceType<I>> template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<T, TIteratorReference<I>> && CAssignableFrom<T&, TIteratorReference<I>> && CMovable<T>)
&& CAssignableFrom<ElementType&, TIteratorReferenceType<I>> && CMovable<ElementType>) FIterator Insert(FConstIterator Iter, I First, S Last)
Iterator Insert(ConstIterator Iter, I First, S Last)
{ {
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator()."));
if constexpr (CForwardIterator<I>) if constexpr (CForwardIterator<I>)
{ {
if (CSizedSentinelFor<S, I>) { checkf(First <= Last, TEXT("Illegal range iterator. Please check First <= Last.")); }
const size_t InsertIndex = Iter - Begin(); const size_t InsertIndex = Iter - Begin();
const size_t Count = Iteration::Distance(First, Last);
if (Count == 0) return Iterator(this, Impl.Pointer + InsertIndex); size_t Count = 0;
if constexpr (CSizedSentinelFor<S, I>)
{
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
Count = Last - First;
}
else for (I Jter = First; Jter != Last; ++Jter) ++Count;
if (Count == 0) return FIterator(this, Impl.Pointer + InsertIndex);
const size_t NumToAllocate = Num() + Count > Max() ? Impl->CalculateSlackGrow(Num() + Count, Max()) : Max(); const size_t NumToAllocate = Num() + Count > Max() ? Impl->CalculateSlackGrow(Num() + Count, Max()) : Max();
@ -431,26 +450,26 @@ public:
if (NumToAllocate != Max()) if (NumToAllocate != Max())
{ {
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = Num(); const size_t NumToDestruct = Num();
Impl.ArrayNum = Num() + Count; Impl.ArrayNum = Num() + Count;
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, InsertIndex); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, InsertIndex);
for (size_t Index = InsertIndex; Index != InsertIndex + Count; ++Index) for (size_t Index = InsertIndex; Index != InsertIndex + Count; ++Index)
{ {
new (Impl.Pointer + Index) ElementType(*First++); new (Impl.Pointer + Index) FElementType(*First++);
} }
Memory::MoveConstruct<ElementType>(Impl.Pointer + InsertIndex + Count, OldAllocation + InsertIndex, NumToDestruct - InsertIndex); Memory::MoveConstruct<FElementType>(Impl.Pointer + InsertIndex + Count, OldAllocation + InsertIndex, NumToDestruct - InsertIndex);
Memory::Destruct(OldAllocation, NumToDestruct); Memory::Destruct(OldAllocation, NumToDestruct);
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
return Iterator(this, Impl.Pointer + InsertIndex); return FIterator(this, Impl.Pointer + InsertIndex);
} }
/* /*
@ -492,7 +511,7 @@ public:
for (size_t TargetIndex = IndexO - 1; TargetIndex != IndexD - 1; --TargetIndex) for (size_t TargetIndex = IndexO - 1; TargetIndex != IndexD - 1; --TargetIndex)
{ {
new (Impl.Pointer + TargetIndex) ElementType(MoveTemp(Impl.Pointer[TargetIndex - Count])); new (Impl.Pointer + TargetIndex) FElementType(MoveTemp(Impl.Pointer[TargetIndex - Count]));
} }
for (size_t TargetIndex = IndexD - 1; TargetIndex != IndexC - 1; --TargetIndex) for (size_t TargetIndex = IndexD - 1; TargetIndex != IndexC - 1; --TargetIndex)
@ -507,14 +526,14 @@ public:
for (size_t TargetIndex = IndexB; TargetIndex != IndexC; ++TargetIndex) for (size_t TargetIndex = IndexB; TargetIndex != IndexC; ++TargetIndex)
{ {
new (Impl.Pointer + TargetIndex) ElementType(*First++); new (Impl.Pointer + TargetIndex) FElementType(*First++);
} }
check(First == Last); check(First == Last);
Impl.ArrayNum = Num() + Count; Impl.ArrayNum = Num() + Count;
return Iterator(this, Impl.Pointer + InsertIndex); return FIterator(this, Impl.Pointer + InsertIndex);
} }
else else
{ {
@ -523,15 +542,22 @@ public:
} }
} }
/** Inserts elements from initializer list before 'Iter' in the container. */ /** Inserts elements from range before 'Iter'. */
FORCEINLINE Iterator Insert(ConstIterator Iter, initializer_list<ElementType> IL) requires (CCopyable<ElementType>) template <CInputRange R> requires (CConstructibleFrom<T, TRangeReference<R>> && CAssignableFrom<T&, TRangeReference<R>> && CMovable<T>)
FORCEINLINE FIterator Insert(FConstIterator Iter, R&& Range)
{ {
return Insert(Iter, Iteration::Begin(IL), Iteration::End(IL)); 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, Ranges::Begin(IL), Ranges::End(IL));
} }
/** Inserts a new element into the container directly before 'Iter'. */ /** Inserts a new element into the container directly before 'Iter'. */
template <typename... Ts> requires (CConstructibleFrom<ElementType, Ts...> && CMovable<ElementType>) template <typename... Ts> requires (CConstructibleFrom<T, Ts...> && CMovable<T>)
Iterator Emplace(ConstIterator Iter, Ts&&... Args) FIterator Emplace(FConstIterator Iter, Ts&&... Args)
{ {
checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter), TEXT("Read access violation. Please check IsValidIterator()."));
@ -543,43 +569,43 @@ public:
if (NumToAllocate != Max()) if (NumToAllocate != Max())
{ {
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = Num(); const size_t NumToDestruct = Num();
Impl.ArrayNum = Num() + 1; Impl.ArrayNum = Num() + 1;
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, InsertIndex); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, InsertIndex);
new (Impl.Pointer + InsertIndex) ElementType(Forward<Ts>(Args)...); new (Impl.Pointer + InsertIndex) FElementType(Forward<Ts>(Args)...);
Memory::MoveConstruct<ElementType>(Impl.Pointer + InsertIndex + 1, OldAllocation + InsertIndex, NumToDestruct - InsertIndex); Memory::MoveConstruct<FElementType>(Impl.Pointer + InsertIndex + 1, OldAllocation + InsertIndex, NumToDestruct - InsertIndex);
Memory::Destruct(OldAllocation, NumToDestruct); Memory::Destruct(OldAllocation, NumToDestruct);
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
return Iterator(this, Impl.Pointer + InsertIndex); return FIterator(this, Impl.Pointer + InsertIndex);
} }
if (InsertIndex != Num()) if (InsertIndex != Num())
{ {
new (Impl.Pointer + Num()) ElementType(MoveTemp(Impl.Pointer[Num() - 1])); new (Impl.Pointer + Num()) FElementType(MoveTemp(Impl.Pointer[Num() - 1]));
for (size_t Index = Num() - 1; Index != InsertIndex; --Index) for (size_t Index = Num() - 1; Index != InsertIndex; --Index)
{ {
Impl.Pointer[Index] = MoveTemp(Impl.Pointer[Index - 1]); Impl.Pointer[Index] = MoveTemp(Impl.Pointer[Index - 1]);
} }
Impl.Pointer[InsertIndex] = ElementType(Forward<Ts>(Args)...); Impl.Pointer[InsertIndex] = FElementType(Forward<Ts>(Args)...);
} }
else new (Impl.Pointer + Num()) ElementType(Forward<Ts>(Args)...); else new (Impl.Pointer + Num()) FElementType(Forward<Ts>(Args)...);
Impl.ArrayNum = Num() + 1; Impl.ArrayNum = Num() + 1;
return Iterator(this, Impl.Pointer + InsertIndex); return FIterator(this, Impl.Pointer + InsertIndex);
} }
/** Removes the element at 'Iter' in the container. Without changing the order of elements. */ /** Removes the element at 'Iter' in the container. Without changing the order of elements. */
FORCEINLINE Iterator StableErase(ConstIterator Iter, bool bAllowShrinking = true) requires (CMovable<ElementType>) FORCEINLINE FIterator StableErase(FConstIterator Iter, bool bAllowShrinking = true) requires (CMovable<T>)
{ {
checkf(IsValidIterator(Iter) && Iter != End(), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter) && Iter != End(), TEXT("Read access violation. Please check IsValidIterator()."));
@ -587,33 +613,33 @@ public:
} }
/** Removes the elements in the range ['First', 'Last') in the container. Without changing the order of elements. */ /** Removes the elements in the range ['First', 'Last') in the container. Without changing the order of elements. */
Iterator StableErase(ConstIterator First, ConstIterator Last, bool bAllowShrinking = true) requires (CMovable<ElementType>) FIterator StableErase(FConstIterator First, FConstIterator Last, bool bAllowShrinking = true) requires (CMovable<T>)
{ {
checkf(IsValidIterator(First) && IsValidIterator(Last) && First <= Last, TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(First) && IsValidIterator(Last) && First <= Last, TEXT("Read access violation. Please check IsValidIterator()."));
const size_t EraseIndex = First - Begin(); const size_t EraseIndex = First - Begin();
const size_t EraseCount = Last - First; const size_t EraseCount = Last - First;
if (EraseCount == 0) return Iterator(this, Impl.Pointer + EraseIndex); if (EraseCount == 0) return FIterator(this, Impl.Pointer + EraseIndex);
const size_t NumToAllocate = bAllowShrinking ? Impl->CalculateSlackShrink(Num() - EraseCount, Max()) : Max(); const size_t NumToAllocate = bAllowShrinking ? Impl->CalculateSlackShrink(Num() - EraseCount, Max()) : Max();
if (NumToAllocate != Max()) if (NumToAllocate != Max())
{ {
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = Num(); const size_t NumToDestruct = Num();
Impl.ArrayNum = Num() - EraseCount; Impl.ArrayNum = Num() - EraseCount;
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, EraseIndex); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, EraseIndex);
Memory::MoveConstruct<ElementType>(Impl.Pointer + EraseIndex, OldAllocation + EraseIndex + EraseCount, NumToDestruct - EraseIndex - EraseCount); Memory::MoveConstruct<FElementType>(Impl.Pointer + EraseIndex, OldAllocation + EraseIndex + EraseCount, NumToDestruct - EraseIndex - EraseCount);
Memory::Destruct(OldAllocation, NumToDestruct); Memory::Destruct(OldAllocation, NumToDestruct);
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
return Iterator(this, Impl.Pointer + EraseIndex); return FIterator(this, Impl.Pointer + EraseIndex);
} }
for (size_t Index = EraseIndex + EraseCount; Index != Num(); ++Index) for (size_t Index = EraseIndex + EraseCount; Index != Num(); ++Index)
@ -625,11 +651,11 @@ public:
Impl.ArrayNum = Num() - EraseCount; Impl.ArrayNum = Num() - EraseCount;
return Iterator(this, Impl.Pointer + EraseIndex); return FIterator(this, Impl.Pointer + EraseIndex);
} }
/** Removes the element at 'Iter' in the container. But it may change the order of elements. */ /** Removes the element at 'Iter' in the container. But it may change the order of elements. */
FORCEINLINE Iterator Erase(ConstIterator Iter, bool bAllowShrinking = true) requires (CMovable<ElementType>) FORCEINLINE FIterator Erase(FConstIterator Iter, bool bAllowShrinking = true) requires (CMovable<T>)
{ {
checkf(IsValidIterator(Iter) && Iter != End(), TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(Iter) && Iter != End(), TEXT("Read access violation. Please check IsValidIterator()."));
@ -637,33 +663,33 @@ public:
} }
/** Removes the elements in the range ['First', 'Last') in the container. But it may change the order of elements. */ /** Removes the elements in the range ['First', 'Last') in the container. But it may change the order of elements. */
Iterator Erase(ConstIterator First, ConstIterator Last, bool bAllowShrinking = true) requires (CMovable<ElementType>) FIterator Erase(FConstIterator First, FConstIterator Last, bool bAllowShrinking = true) requires (CMovable<T>)
{ {
checkf(IsValidIterator(First) && IsValidIterator(Last) && First <= Last, TEXT("Read access violation. Please check IsValidIterator().")); checkf(IsValidIterator(First) && IsValidIterator(Last) && First <= Last, TEXT("Read access violation. Please check IsValidIterator()."));
const size_t EraseIndex = First - Begin(); const size_t EraseIndex = First - Begin();
const size_t EraseCount = Last - First; const size_t EraseCount = Last - First;
if (EraseCount == 0) return Iterator(this, Impl.Pointer + EraseIndex); if (EraseCount == 0) return FIterator(this, Impl.Pointer + EraseIndex);
const size_t NumToAllocate = bAllowShrinking ? Impl->CalculateSlackShrink(Num() - EraseCount, Max()) : Max(); const size_t NumToAllocate = bAllowShrinking ? Impl->CalculateSlackShrink(Num() - EraseCount, Max()) : Max();
if (NumToAllocate != Max()) if (NumToAllocate != Max())
{ {
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = Num(); const size_t NumToDestruct = Num();
Impl.ArrayNum = Num() - EraseCount; Impl.ArrayNum = Num() - EraseCount;
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, EraseIndex); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, EraseIndex);
Memory::MoveConstruct<ElementType>(Impl.Pointer + EraseIndex, OldAllocation + EraseIndex + EraseCount, NumToDestruct - EraseIndex - EraseCount); Memory::MoveConstruct<FElementType>(Impl.Pointer + EraseIndex, OldAllocation + EraseIndex + EraseCount, NumToDestruct - EraseIndex - EraseCount);
Memory::Destruct(OldAllocation, NumToDestruct); Memory::Destruct(OldAllocation, NumToDestruct);
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
return Iterator(this, Impl.Pointer + EraseIndex); return FIterator(this, Impl.Pointer + EraseIndex);
} }
for (size_t Index = 0; Index != EraseCount; ++Index) for (size_t Index = 0; Index != EraseCount; ++Index)
@ -677,24 +703,24 @@ public:
Impl.ArrayNum = Num() - EraseCount; Impl.ArrayNum = Num() - EraseCount;
return Iterator(this, Impl.Pointer + EraseIndex); return FIterator(this, Impl.Pointer + EraseIndex);
} }
/** Appends the given element value to the end of the container. */ /** Appends the given element value to the end of the container. */
FORCEINLINE void PushBack(const ElementType& InValue) requires (CCopyable<ElementType>) FORCEINLINE void PushBack(const FElementType& InValue) requires (CCopyable<T>)
{ {
EmplaceBack(InValue); EmplaceBack(InValue);
} }
/** Appends the given element value to the end of the container. */ /** Appends the given element value to the end of the container. */
FORCEINLINE void PushBack(ElementType&& InValue) requires (CMovable<ElementType>) FORCEINLINE void PushBack(FElementType&& InValue) requires (CMovable<T>)
{ {
EmplaceBack(MoveTemp(InValue)); EmplaceBack(MoveTemp(InValue));
} }
/** Appends a new element to the end of the container. */ /** Appends a new element to the end of the container. */
template <typename... Ts> requires (CConstructibleFrom<ElementType, Ts...> && CMovable<ElementType>) template <typename... Ts> requires (CConstructibleFrom<T, Ts...> && CMovable<T>)
ElementType& EmplaceBack(Ts&&... Args) FElementType& EmplaceBack(Ts&&... Args)
{ {
const size_t NumToAllocate = Num() + 1 > Max() ? Impl->CalculateSlackGrow(Num() + 1, Max()) : Max(); const size_t NumToAllocate = Num() + 1 > Max() ? Impl->CalculateSlackGrow(Num() + 1, Max()) : Max();
@ -702,15 +728,15 @@ public:
if (NumToAllocate != Max()) if (NumToAllocate != Max())
{ {
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = Num(); const size_t NumToDestruct = Num();
Impl.ArrayNum = Num() + 1; Impl.ArrayNum = Num() + 1;
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, Num() - 1); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, Num() - 1);
new (Impl.Pointer + Num() - 1) ElementType(Forward<Ts>(Args)...); new (Impl.Pointer + Num() - 1) FElementType(Forward<Ts>(Args)...);
Memory::Destruct(OldAllocation, NumToDestruct); Memory::Destruct(OldAllocation, NumToDestruct);
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
@ -718,7 +744,7 @@ public:
return Impl.Pointer[Num() - 1]; return Impl.Pointer[Num() - 1];
} }
new (Impl.Pointer + Num()) ElementType(Forward<Ts>(Args)...); new (Impl.Pointer + Num()) FElementType(Forward<Ts>(Args)...);
Impl.ArrayNum = Num() + 1; Impl.ArrayNum = Num() + 1;
@ -726,13 +752,13 @@ public:
} }
/** Removes the last element of the container. The array cannot be empty. */ /** Removes the last element of the container. The array cannot be empty. */
FORCEINLINE void PopBack(bool bAllowShrinking = true) requires (CMovable<ElementType>) FORCEINLINE void PopBack(bool bAllowShrinking = true) requires (CMovable<T>)
{ {
Erase(End() - 1, bAllowShrinking); Erase(End() - 1, bAllowShrinking);
} }
/** Resizes the container to contain 'Count' elements. Additional default elements are appended. */ /** Resizes the container to contain 'Count' elements. Additional default elements are appended. */
void SetNum(size_t Count, bool bAllowShrinking = true) requires (CDefaultConstructible<ElementType> && CMovable<ElementType>) void SetNum(size_t Count, bool bAllowShrinking = true) requires (CDefaultConstructible<T> && CMovable<T>)
{ {
size_t NumToAllocate = Count; size_t NumToAllocate = Count;
@ -741,8 +767,8 @@ public:
if (NumToAllocate != Max()) if (NumToAllocate != Max())
{ {
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = Num(); const size_t NumToDestruct = Num();
Impl.ArrayNum = Count; Impl.ArrayNum = Count;
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
@ -750,12 +776,12 @@ public:
if (NumToDestruct <= Num()) if (NumToDestruct <= Num())
{ {
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, NumToDestruct); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, NumToDestruct);
Memory::DefaultConstruct<ElementType>(Impl.Pointer + NumToDestruct, Num() - NumToDestruct); Memory::DefaultConstruct<FElementType>(Impl.Pointer + NumToDestruct, Num() - NumToDestruct);
} }
else else
{ {
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, Num()); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, Num());
} }
Memory::Destruct(OldAllocation, NumToDestruct); Memory::Destruct(OldAllocation, NumToDestruct);
@ -770,7 +796,7 @@ public:
} }
else if (Count <= Max()) else if (Count <= Max())
{ {
Memory::DefaultConstruct<ElementType>(Impl.Pointer + Num(), Count - Num()); Memory::DefaultConstruct<FElementType>(Impl.Pointer + Num(), Count - Num());
} }
else check_no_entry(); else check_no_entry();
@ -778,7 +804,7 @@ public:
} }
/** Resizes the container to contain 'Count' elements. Additional copies of 'InValue' are appended. */ /** Resizes the container to contain 'Count' elements. Additional copies of 'InValue' are appended. */
void SetNum(size_t Count, const ElementType& InValue, bool bAllowShrinking = true) requires (CCopyConstructible<ElementType> && CMovable<ElementType>) void SetNum(size_t Count, const FElementType& InValue, bool bAllowShrinking = true) requires (CCopyConstructible<T> && CMovable<T>)
{ {
size_t NumToAllocate = Count; size_t NumToAllocate = Count;
@ -787,8 +813,8 @@ public:
if (NumToAllocate != Max()) if (NumToAllocate != Max())
{ {
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = Num(); const size_t NumToDestruct = Num();
Impl.ArrayNum = Count; Impl.ArrayNum = Count;
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
@ -796,16 +822,16 @@ public:
if (NumToDestruct <= Num()) if (NumToDestruct <= Num())
{ {
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, NumToDestruct); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, NumToDestruct);
for (size_t Index = NumToDestruct; Index != Num(); ++Index) for (size_t Index = NumToDestruct; Index != Num(); ++Index)
{ {
new (Impl.Pointer + Index) ElementType(InValue); new (Impl.Pointer + Index) FElementType(InValue);
} }
} }
else else
{ {
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, Num()); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, Num());
} }
Memory::Destruct(OldAllocation, NumToDestruct); Memory::Destruct(OldAllocation, NumToDestruct);
@ -822,7 +848,7 @@ public:
{ {
for (size_t Index = Num(); Index != Count; ++Index) for (size_t Index = Num(); Index != Count; ++Index)
{ {
new (Impl.Pointer + Index) ElementType(InValue); new (Impl.Pointer + Index) FElementType(InValue);
} }
} }
else check_no_entry(); else check_no_entry();
@ -831,19 +857,19 @@ public:
} }
/** Increase the max capacity of the array to a value that's greater or equal to 'Count'. */ /** Increase the max capacity of the array to a value that's greater or equal to 'Count'. */
void Reserve(size_t Count) requires (CMovable<ElementType>) void Reserve(size_t Count) requires (CMovable<T>)
{ {
if (Count <= Max()) return; if (Count <= Max()) return;
const size_t NumToAllocate = Impl->CalculateSlackReserve(Count); const size_t NumToAllocate = Impl->CalculateSlackReserve(Count);
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
check(NumToAllocate > Max()); check(NumToAllocate > Max());
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, Num()); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, Num());
Memory::Destruct(OldAllocation, Num()); Memory::Destruct(OldAllocation, Num());
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
@ -858,32 +884,32 @@ public:
if (NumToAllocate == Max()) return; if (NumToAllocate == Max()) return;
ElementType* OldAllocation = Impl.Pointer; FElementType* OldAllocation = Impl.Pointer;
Impl.ArrayMax = NumToAllocate; Impl.ArrayMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(Max()); Impl.Pointer = Impl->Allocate(Max());
Memory::MoveConstruct<ElementType>(Impl.Pointer, OldAllocation, Num()); Memory::MoveConstruct<FElementType>(Impl.Pointer, OldAllocation, Num());
Memory::Destruct(OldAllocation, Num()); Memory::Destruct(OldAllocation, Num());
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
} }
/** @return The pointer to the underlying element storage. */ /** @return The pointer to the underlying element storage. */
NODISCARD FORCEINLINE ElementType* GetData() { return Impl.Pointer; } NODISCARD FORCEINLINE FElementType* GetData() { return Impl.Pointer; }
NODISCARD FORCEINLINE const ElementType* GetData() const { return Impl.Pointer; } NODISCARD FORCEINLINE const FElementType* GetData() const { return Impl.Pointer; }
/** @return The iterator to the first or end element. */ /** @return The iterator to the first or end element. */
NODISCARD FORCEINLINE Iterator Begin() { return Iterator(this, Impl.Pointer); } NODISCARD FORCEINLINE FIterator Begin() { return FIterator(this, Impl.Pointer); }
NODISCARD FORCEINLINE ConstIterator Begin() const { return ConstIterator(this, Impl.Pointer); } NODISCARD FORCEINLINE FConstIterator Begin() const { return FConstIterator(this, Impl.Pointer); }
NODISCARD FORCEINLINE Iterator End() { return Iterator(this, Impl.Pointer + Num()); } NODISCARD FORCEINLINE FIterator End() { return FIterator(this, Impl.Pointer + Num()); }
NODISCARD FORCEINLINE ConstIterator End() const { return ConstIterator(this, Impl.Pointer + Num()); } NODISCARD FORCEINLINE FConstIterator End() const { return FConstIterator(this, Impl.Pointer + Num()); }
/** @return The reverse iterator to the first or end element. */ /** @return The reverse iterator to the first or end element. */
NODISCARD FORCEINLINE ReverseIterator RBegin() { return ReverseIterator(End()); } NODISCARD FORCEINLINE FReverseIterator RBegin() { return FReverseIterator(End()); }
NODISCARD FORCEINLINE ConstReverseIterator RBegin() const { return ConstReverseIterator(End()); } NODISCARD FORCEINLINE FConstReverseIterator RBegin() const { return FConstReverseIterator(End()); }
NODISCARD FORCEINLINE ReverseIterator REnd() { return ReverseIterator(Begin()); } NODISCARD FORCEINLINE FReverseIterator REnd() { return FReverseIterator(Begin()); }
NODISCARD FORCEINLINE ConstReverseIterator REnd() const { return ConstReverseIterator(Begin()); } NODISCARD FORCEINLINE FConstReverseIterator REnd() const { return FConstReverseIterator(Begin()); }
/** @return The number of elements in the container. */ /** @return The number of elements in the container. */
NODISCARD FORCEINLINE size_t Num() const { return Impl.ArrayNum; } NODISCARD FORCEINLINE size_t Num() const { return Impl.ArrayNum; }
@ -895,17 +921,17 @@ public:
NODISCARD FORCEINLINE bool IsEmpty() const { return Num() == 0; } NODISCARD FORCEINLINE bool IsEmpty() const { return Num() == 0; }
/** @return true if the iterator is valid, false otherwise. */ /** @return true if the iterator is valid, false otherwise. */
NODISCARD FORCEINLINE bool IsValidIterator(ConstIterator Iter) const { return Begin() <= Iter && Iter <= End(); } NODISCARD FORCEINLINE bool IsValidIterator(FConstIterator Iter) const { return Begin() <= Iter && Iter <= End(); }
/** @return The reference to the requested element. */ /** @return The reference to the requested element. */
NODISCARD FORCEINLINE ElementType& operator[](size_t Index) { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return Impl.Pointer[Index]; } NODISCARD FORCEINLINE FElementType& operator[](size_t Index) { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return Impl.Pointer[Index]; }
NODISCARD FORCEINLINE const ElementType& operator[](size_t Index) const { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return Impl.Pointer[Index]; } NODISCARD FORCEINLINE const FElementType& operator[](size_t Index) const { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return Impl.Pointer[Index]; }
/** @return The reference to the first or last element. */ /** @return The reference to the first or last element. */
NODISCARD FORCEINLINE ElementType& Front() { return *Begin(); } NODISCARD FORCEINLINE FElementType& Front() { return *Begin(); }
NODISCARD FORCEINLINE const ElementType& Front() const { return *Begin(); } NODISCARD FORCEINLINE const FElementType& Front() const { return *Begin(); }
NODISCARD FORCEINLINE ElementType& Back() { return *(End() - 1); } NODISCARD FORCEINLINE FElementType& Back() { return *(End() - 1); }
NODISCARD FORCEINLINE const ElementType& Back() const { return *(End() - 1); } NODISCARD FORCEINLINE const FElementType& Back() const { return *(End() - 1); }
/** Erases all elements from the container. After this call, Num() returns zero. */ /** Erases all elements from the container. After this call, Num() returns zero. */
void Reset(bool bAllowShrinking = true) void Reset(bool bAllowShrinking = true)
@ -929,11 +955,11 @@ public:
} }
/** Overloads the GetTypeHash algorithm for TArray. */ /** Overloads the GetTypeHash algorithm for TArray. */
NODISCARD friend FORCEINLINE size_t GetTypeHash(const TArray& A) requires (CHashable<ElementType>) NODISCARD friend FORCEINLINE size_t GetTypeHash(const TArray& A) requires (CHashable<T>)
{ {
size_t Result = 0; size_t Result = 0;
for (ConstIterator Iter = A.Begin(); Iter != A.End(); ++Iter) for (FConstIterator Iter = A.Begin(); Iter != A.End(); ++Iter)
{ {
Result = HashCombine(Result, GetTypeHash(*Iter)); Result = HashCombine(Result, GetTypeHash(*Iter));
} }
@ -942,7 +968,7 @@ public:
} }
/** Overloads the Swap algorithm for TArray. */ /** Overloads the Swap algorithm for TArray. */
friend void Swap(TArray& A, TArray& B) requires (CMovable<ElementType>) friend void Swap(TArray& A, TArray& B) requires (CMovable<T>)
{ {
const bool bIsTransferable = const bool bIsTransferable =
A.Impl->IsTransferable(A.Impl.Pointer) && A.Impl->IsTransferable(A.Impl.Pointer) &&
@ -966,13 +992,13 @@ public:
private: private:
ALLOCATOR_WRAPPER_BEGIN(AllocatorType, ElementType, Impl) ALLOCATOR_WRAPPER_BEGIN(FAllocatorType, FElementType, Impl)
{ {
size_t ArrayNum; size_t ArrayNum;
size_t ArrayMax; size_t ArrayMax;
ElementType* Pointer; FElementType* Pointer;
} }
ALLOCATOR_WRAPPER_END(AllocatorType, ElementType, Impl) ALLOCATOR_WRAPPER_END(FAllocatorType, FElementType, Impl)
private: private:
@ -981,7 +1007,7 @@ private:
{ {
public: public:
using ElementType = TRemoveCV<T>; using FElementType = T;
FORCEINLINE TIteratorImpl() = default; FORCEINLINE TIteratorImpl() = default;
@ -1058,7 +1084,10 @@ private:
}; };
template <typename I, typename S> template <typename I, typename S>
TArray(I, S) -> TArray<TIteratorElementType<I>>; TArray(I, S) -> TArray<TIteratorElement<I>>;
template <typename R>
TArray(R) -> TArray<TRangeElement<R>>;
template <typename T> template <typename T>
TArray(initializer_list<T>) -> TArray<T>; TArray(initializer_list<T>) -> TArray<T>;

View File

@ -1,16 +1,16 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Memory/Address.h" #include "TypeTraits/TypeTraits.h"
#include "Memory/Allocator.h"
#include "Containers/Array.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "Templates/TypeHash.h" #include "Templates/TypeHash.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 "Containers/StaticArray.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Compare.h" #include "Miscellaneous/Compare.h"
#include "Miscellaneous/Iterator.h"
#include "Miscellaneous/Container.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
@ -29,15 +29,15 @@ class TArrayView
{ {
public: public:
using ElementType = T; using FElementType = TRemoveCV<T>;
using Reference = T&; using FReference = T&;
class Iterator; class FIterator;
using ReverseIterator = TReverseIterator<Iterator>; using FReverseIterator = TReverseIterator<FIterator>;
static_assert(CContiguousIterator<Iterator>); static_assert(CContiguousIterator<FIterator>);
static constexpr size_t Extent = InExtent; static constexpr size_t Extent = InExtent;
@ -53,7 +53,7 @@ public:
} }
/** Constructs an array view that is a view over the range ['InFirst', 'InFirst' + 'Count'). */ /** Constructs an array view that is a view over the range ['InFirst', 'InFirst' + 'Count'). */
template <CContiguousIterator I> requires (CConvertibleTo<TIteratorElementType<I>(*)[], ElementType(*)[]>) template <CContiguousIterator I> requires (CConvertibleTo<TIteratorReference<I>, T> && CSameAs<TRemoveCVRef<TIteratorReference<I>>, TRemoveCVRef<T>>)
FORCEINLINE constexpr explicit (Extent != DynamicExtent) TArrayView(I InFirst, size_t InCount) FORCEINLINE constexpr explicit (Extent != DynamicExtent) TArrayView(I InFirst, size_t InCount)
{ {
checkf(Extent == DynamicExtent || Extent == InCount, TEXT("Illegal range count. Please check InCount.")); checkf(Extent == DynamicExtent || Extent == InCount, TEXT("Illegal range count. Please check InCount."));
@ -67,7 +67,7 @@ public:
} }
/** Constructs an array view that is a view over the range ['InFirst', 'InLast'). */ /** Constructs an array view that is a view over the range ['InFirst', 'InLast'). */
template <CContiguousIterator I, CSizedSentinelFor<I> S> requires (CConvertibleTo<TIteratorElementType<I>(*)[], ElementType(*)[]>) template <CContiguousIterator I, CSizedSentinelFor<I> S> requires (CConvertibleTo<TIteratorReference<I>, T> && CSameAs<TRemoveCVRef<TIteratorReference<I>>, TRemoveCVRef<T>>)
FORCEINLINE constexpr explicit (Extent != DynamicExtent) TArrayView(I InFirst, S InLast) FORCEINLINE constexpr explicit (Extent != DynamicExtent) TArrayView(I InFirst, S InLast)
{ {
checkf(Extent == DynamicExtent || Extent == InLast - InFirst, TEXT("Illegal range iterator. Please check InLast - InFirst.")); checkf(Extent == DynamicExtent || Extent == InLast - InFirst, TEXT("Illegal range iterator. Please check InLast - InFirst."));
@ -82,7 +82,7 @@ public:
/** Constructs an array view that is a view over the array 'InArray'. */ /** Constructs an array view that is a view over the array 'InArray'. */
template <size_t N> requires (Extent == DynamicExtent || N == Extent) template <size_t N> requires (Extent == DynamicExtent || N == Extent)
FORCEINLINE constexpr TArrayView(ElementType(&InArray)[N]) FORCEINLINE constexpr TArrayView(FElementType(&InArray)[N])
{ {
Impl.Pointer = InArray; Impl.Pointer = InArray;
@ -93,23 +93,23 @@ public:
} }
/** Constructs an array view that is a view over the array 'InArray'. */ /** Constructs an array view that is a view over the array 'InArray'. */
template <typename U, size_t N> requires (CConvertibleTo<U(*)[], ElementType(*)[]>) template <typename U, size_t N> requires (CConvertibleTo<U(*)[], FElementType(*)[]>)
FORCEINLINE constexpr TArrayView(TStaticArray<U, N>& InArray) : TArrayView(InArray.GetData(), InArray.Num()) { } FORCEINLINE constexpr TArrayView(TStaticArray<U, N>& InArray) : TArrayView(InArray.GetData(), InArray.Num()) { }
/** Constructs an array view that is a view over the array 'InArray'. */ /** Constructs an array view that is a view over the array 'InArray'. */
template <typename U, size_t N> requires (CConvertibleTo<const U(*)[], ElementType(*)[]>) template <typename U, size_t N> requires (CConvertibleTo<const U(*)[], FElementType(*)[]>)
FORCEINLINE constexpr TArrayView(const TStaticArray<U, N>& InArray) : TArrayView(InArray.GetData(), InArray.Num()) { } FORCEINLINE constexpr TArrayView(const TStaticArray<U, N>& InArray) : TArrayView(InArray.GetData(), InArray.Num()) { }
/** Constructs an array view that is a view over the array 'InArray'. */ /** Constructs an array view that is a view over the array 'InArray'. */
template <typename U, typename Allocator> requires (CConvertibleTo<U(*)[], ElementType(*)[]>) template <typename U, typename Allocator> requires (CConvertibleTo<U(*)[], FElementType(*)[]>)
FORCEINLINE constexpr TArrayView(TArray<U, Allocator>& InArray) : TArrayView(InArray.GetData(), InArray.Num()) { } FORCEINLINE constexpr TArrayView(TArray<U, Allocator>& InArray) : TArrayView(InArray.GetData(), InArray.Num()) { }
/** Constructs an array view that is a view over the array 'InArray'. */ /** Constructs an array view that is a view over the array 'InArray'. */
template <typename U, typename Allocator> requires (CConvertibleTo<const U(*)[], ElementType(*)[]>) template <typename U, typename Allocator> requires (CConvertibleTo<const U(*)[], FElementType(*)[]>)
FORCEINLINE constexpr TArrayView(const TArray<U, Allocator>& InArray) : TArrayView(InArray.GetData(), InArray.Num()) { } FORCEINLINE constexpr TArrayView(const TArray<U, Allocator>& InArray) : TArrayView(InArray.GetData(), InArray.Num()) { }
/** Converting constructor from another array view 'InValue'. */ /** Converting constructor from another array view 'InValue'. */
template <typename U, size_t N> requires ((Extent == DynamicExtent || N == DynamicExtent || N == Extent) && CConvertibleTo<U(*)[], ElementType(*)[]>) template <typename U, size_t N> requires ((Extent == DynamicExtent || N == DynamicExtent || N == Extent) && CConvertibleTo<U(*)[], FElementType(*)[]>)
FORCEINLINE constexpr explicit (Extent != DynamicExtent && N == DynamicExtent) TArrayView(TArrayView<U, N> InValue) FORCEINLINE constexpr explicit (Extent != DynamicExtent && N == DynamicExtent) TArrayView(TArrayView<U, N> InValue)
{ {
checkf(Extent == DynamicExtent || Extent == InValue.Num(), TEXT("Illegal view extent. Please check InValue.Num().")); checkf(Extent == DynamicExtent || Extent == InValue.Num(), TEXT("Illegal view extent. Please check InValue.Num()."));
@ -129,7 +129,7 @@ public:
FORCEINLINE constexpr TArrayView& operator=(const TArrayView&) noexcept = default; FORCEINLINE constexpr TArrayView& operator=(const TArrayView&) noexcept = default;
/** Compares the contents of two array views. */ /** Compares the contents of two array views. */
NODISCARD friend constexpr bool operator==(TArrayView LHS, TArrayView RHS) requires (CWeaklyEqualityComparable<ElementType>) NODISCARD friend constexpr bool operator==(TArrayView LHS, TArrayView RHS) requires (CWeaklyEqualityComparable<FElementType>)
{ {
if (LHS.Num() != RHS.Num()) return false; if (LHS.Num() != RHS.Num()) return false;
@ -142,7 +142,7 @@ public:
} }
/** Compares the contents of two array views. */ /** Compares the contents of two array views. */
NODISCARD friend constexpr auto operator<=>(TArrayView LHS, TArrayView RHS) requires (CSynthThreeWayComparable<ElementType>) NODISCARD friend constexpr auto operator<=>(TArrayView LHS, TArrayView RHS) requires (CSynthThreeWayComparable<FElementType>)
{ {
const size_t NumToCompare = LHS.Num() < RHS.Num() ? LHS.Num() : RHS.Num(); const size_t NumToCompare = LHS.Num() < RHS.Num() ? LHS.Num() : RHS.Num();
@ -156,36 +156,36 @@ public:
/** Obtains an array view that is a view over the first 'Count' elements of this array view. */ /** Obtains an array view that is a view over the first 'Count' elements of this array view. */
template <size_t Count> requires (Extent == DynamicExtent || Extent >= Count) template <size_t Count> requires (Extent == DynamicExtent || Extent >= Count)
NODISCARD FORCEINLINE constexpr TArrayView<ElementType, Count> First() const NODISCARD FORCEINLINE constexpr TArrayView<T, Count> First() const
{ {
checkf(Count <= Num(), TEXT("Illegal subview range. Please check Count.")); checkf(Count <= Num(), TEXT("Illegal subview range. Please check Count."));
return TArrayView<ElementType, Count>(Begin(), Count); return TArrayView<T, Count>(Begin(), Count);
} }
/** Obtains an array view that is a view over the first 'Count' elements of this array view. */ /** Obtains an array view that is a view over the first 'Count' elements of this array view. */
NODISCARD FORCEINLINE constexpr TArrayView<ElementType, DynamicExtent> First(size_t Count) const NODISCARD FORCEINLINE constexpr TArrayView<T, DynamicExtent> First(size_t Count) const
{ {
checkf(Count <= Num(), TEXT("Illegal subview range. Please check Count.")); checkf(Count <= Num(), TEXT("Illegal subview range. Please check Count."));
return TArrayView<ElementType, DynamicExtent>(Begin(), Count); return TArrayView<T, DynamicExtent>(Begin(), Count);
} }
/** Obtains an array view that is a view over the last 'Count' elements of this array view. */ /** Obtains an array view that is a view over the last 'Count' elements of this array view. */
template <size_t Count> requires (Extent == DynamicExtent || Extent >= Count) template <size_t Count> requires (Extent == DynamicExtent || Extent >= Count)
NODISCARD FORCEINLINE constexpr TArrayView<ElementType, Count> Last() const NODISCARD FORCEINLINE constexpr TArrayView<T, Count> Last() const
{ {
checkf(Count <= Num(), TEXT("Illegal subview range. Please check Count.")); checkf(Count <= Num(), TEXT("Illegal subview range. Please check Count."));
return TArrayView<ElementType, Count>(End() - Count, Count); return TArrayView<T, Count>(End() - Count, Count);
} }
/** Obtains an array view that is a view over the last 'Count' elements of this array view. */ /** Obtains an array view that is a view over the last 'Count' elements of this array view. */
NODISCARD FORCEINLINE constexpr TArrayView<ElementType, DynamicExtent> Last(size_t Count) const NODISCARD FORCEINLINE constexpr TArrayView<T, DynamicExtent> Last(size_t Count) const
{ {
checkf(Count <= Num(), TEXT("Illegal subview range. Please check Count.")); checkf(Count <= Num(), TEXT("Illegal subview range. Please check Count."));
return TArrayView<ElementType, DynamicExtent>(End() - Count, Count); return TArrayView<T, DynamicExtent>(End() - Count, Count);
} }
/** Obtains an array view that is a view over the 'Count' elements of this array view starting at 'Offset'. */ /** Obtains an array view that is a view over the 'Count' elements of this array view starting at 'Offset'. */
@ -198,11 +198,11 @@ public:
if constexpr (Count != DynamicExtent) if constexpr (Count != DynamicExtent)
{ {
return TArrayView<ElementType, SubviewExtent>(Begin() + Offset, Count); return TArrayView<T, SubviewExtent>(Begin() + Offset, Count);
} }
else else
{ {
return TArrayView<ElementType, SubviewExtent>(Begin() + Offset, Num() - Offset); return TArrayView<T, SubviewExtent>(Begin() + Offset, Num() - Offset);
} }
} }
@ -213,20 +213,20 @@ public:
if (Count != DynamicExtent) if (Count != DynamicExtent)
{ {
return TArrayView<ElementType, DynamicExtent>(Begin() + Offset, Count); return TArrayView<T, DynamicExtent>(Begin() + Offset, Count);
} }
else else
{ {
return TArrayView<ElementType, DynamicExtent>(Begin() + Offset, Num() - Offset); return TArrayView<T, DynamicExtent>(Begin() + Offset, Num() - Offset);
} }
} }
/** Obtains an array view to the object representation of the elements of the array view. */ /** Obtains an array view to the object representation of the elements of the array view. */
NODISCARD FORCEINLINE constexpr auto AsBytes() NODISCARD FORCEINLINE constexpr auto AsBytes()
{ {
constexpr size_t BytesExtent = Extent != DynamicExtent ? sizeof(ElementType) * Extent : DynamicExtent; constexpr size_t BytesExtent = Extent != DynamicExtent ? sizeof(FElementType) * Extent : DynamicExtent;
if constexpr (!CConst<ElementType>) if constexpr (!CConst<FElementType>)
{ {
return TArrayView<uint8, BytesExtent>(reinterpret_cast<uint8*>(GetData()), NumBytes()); return TArrayView<uint8, BytesExtent>(reinterpret_cast<uint8*>(GetData()), NumBytes());
} }
@ -239,47 +239,47 @@ public:
/** Obtains an array view to the object representation of the elements of the array view. */ /** Obtains an array view to the object representation of the elements of the array view. */
NODISCARD FORCEINLINE constexpr auto AsBytes() const NODISCARD FORCEINLINE constexpr auto AsBytes() const
{ {
constexpr size_t BytesExtent = Extent != DynamicExtent ? sizeof(ElementType) * Extent : DynamicExtent; constexpr size_t BytesExtent = Extent != DynamicExtent ? sizeof(FElementType) * Extent : DynamicExtent;
return TArrayView<const uint8, BytesExtent>(reinterpret_cast<const uint8*>(GetData()), NumBytes()); return TArrayView<const uint8, BytesExtent>(reinterpret_cast<const uint8*>(GetData()), NumBytes());
} }
/** @return The pointer to the underlying element storage. */ /** @return The pointer to the underlying element storage. */
NODISCARD FORCEINLINE constexpr ElementType* GetData() const { return Impl.Pointer; } NODISCARD FORCEINLINE constexpr T* GetData() const { return Impl.Pointer; }
/** @return The iterator to the first or end element. */ /** @return The iterator to the first or end element. */
NODISCARD FORCEINLINE constexpr Iterator Begin() const { return Iterator(this, Impl.Pointer); } NODISCARD FORCEINLINE constexpr FIterator Begin() const { return FIterator(this, Impl.Pointer); }
NODISCARD FORCEINLINE constexpr Iterator End() const { return Iterator(this, Impl.Pointer + Num()); } NODISCARD FORCEINLINE constexpr FIterator End() const { return FIterator(this, Impl.Pointer + Num()); }
/** @return The reverse iterator to the first or end element. */ /** @return The reverse iterator to the first or end element. */
NODISCARD FORCEINLINE constexpr ReverseIterator RBegin() const { return ReverseIterator(End()); } NODISCARD FORCEINLINE constexpr FReverseIterator RBegin() const { return FReverseIterator(End()); }
NODISCARD FORCEINLINE constexpr ReverseIterator REnd() const { return ReverseIterator(Begin()); } NODISCARD FORCEINLINE constexpr FReverseIterator REnd() const { return FReverseIterator(Begin()); }
/** @return The number of elements in the container. */ /** @return The number of elements in the container. */
NODISCARD FORCEINLINE constexpr size_t Num() const { if constexpr (Extent == DynamicExtent) { return Impl.ArrayNum; } return Extent; } NODISCARD FORCEINLINE constexpr size_t Num() const { if constexpr (Extent == DynamicExtent) { return Impl.ArrayNum; } return Extent; }
/** @return The number of bytes in the container. */ /** @return The number of bytes in the container. */
NODISCARD FORCEINLINE constexpr size_t NumBytes() const { return Num() * sizeof(ElementType); } NODISCARD FORCEINLINE constexpr size_t NumBytes() const { return Num() * sizeof(FElementType); }
/** @return true if the container is empty, false otherwise. */ /** @return true if the container is empty, false otherwise. */
NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return Num() == 0; } NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return Num() == 0; }
/** @return true if the iterator is valid, false otherwise. */ /** @return true if the iterator is valid, false otherwise. */
NODISCARD FORCEINLINE constexpr bool IsValidIterator(Iterator Iter) const { return Begin() <= Iter && Iter <= End(); } NODISCARD FORCEINLINE constexpr bool IsValidIterator(FIterator Iter) const { return Begin() <= Iter && Iter <= End(); }
/** @return The reference to the requested element. */ /** @return The reference to the requested element. */
NODISCARD FORCEINLINE constexpr Reference operator[](size_t Index) const { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return Impl.Pointer[Index]; } NODISCARD FORCEINLINE constexpr FReference operator[](size_t Index) const { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return Impl.Pointer[Index]; }
/** @return The reference to the first or last element. */ /** @return The reference to the first or last element. */
NODISCARD FORCEINLINE constexpr Reference Front() const { return *Begin(); } NODISCARD FORCEINLINE constexpr FReference Front() const { return *Begin(); }
NODISCARD FORCEINLINE constexpr Reference Back() const { return *(End() - 1); } NODISCARD FORCEINLINE constexpr FReference Back() const { return *(End() - 1); }
/** Overloads the GetTypeHash algorithm for TArrayView. */ /** Overloads the GetTypeHash algorithm for TArrayView. */
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(TArrayView A) requires (CHashable<ElementType>) NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(TArrayView A) requires (CHashable<FElementType>)
{ {
size_t Result = 0; size_t Result = 0;
for (Iterator Iter = A.Begin(); Iter != A.End(); ++Iter) for (FIterator Iter = A.Begin(); Iter != A.End(); ++Iter)
{ {
Result = HashCombine(Result, GetTypeHash(*Iter)); Result = HashCombine(Result, GetTypeHash(*Iter));
} }
@ -291,7 +291,7 @@ public:
private: private:
struct FImplWithoutNum { ElementType* Pointer; }; struct FImplWithoutNum { T* Pointer; };
struct FImplWithNum : FImplWithoutNum { size_t ArrayNum; }; struct FImplWithNum : FImplWithoutNum { size_t ArrayNum; };
@ -299,42 +299,42 @@ private:
public: public:
class Iterator final class FIterator final
{ {
public: public:
using ElementType = TRemoveCV<T>; using FElementType = TRemoveCV<T>;
FORCEINLINE constexpr Iterator() = default; FORCEINLINE constexpr FIterator() = default;
FORCEINLINE constexpr Iterator(const Iterator&) = default; FORCEINLINE constexpr FIterator(const FIterator&) = default;
FORCEINLINE constexpr Iterator(Iterator&&) = default; FORCEINLINE constexpr FIterator(FIterator&&) = default;
FORCEINLINE constexpr Iterator& operator=(const Iterator&) = default; FORCEINLINE constexpr FIterator& operator=(const FIterator&) = default;
FORCEINLINE constexpr Iterator& operator=(Iterator&&) = default; FORCEINLINE constexpr FIterator& operator=(FIterator&&) = default;
NODISCARD friend FORCEINLINE constexpr bool operator==(const Iterator& LHS, const Iterator& RHS) { return LHS.Pointer == RHS.Pointer; } NODISCARD friend FORCEINLINE constexpr bool operator==(const FIterator& LHS, const FIterator& RHS) { return LHS.Pointer == RHS.Pointer; }
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const Iterator& LHS, const Iterator& RHS) { return LHS.Pointer <=> RHS.Pointer; } NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const FIterator& LHS, const FIterator& RHS) { return LHS.Pointer <=> RHS.Pointer; }
NODISCARD FORCEINLINE constexpr T& operator*() const { CheckThis(true ); return *Pointer; } NODISCARD FORCEINLINE constexpr T& operator*() const { CheckThis(true ); return *Pointer; }
NODISCARD FORCEINLINE constexpr T* operator->() const { CheckThis(false); return Pointer; } NODISCARD FORCEINLINE constexpr T* operator->() const { CheckThis(false); return Pointer; }
NODISCARD FORCEINLINE constexpr T& operator[](ptrdiff Index) const { Iterator Temp = *this + Index; return *Temp; } NODISCARD FORCEINLINE constexpr T& operator[](ptrdiff Index) const { FIterator Temp = *this + Index; return *Temp; }
FORCEINLINE constexpr Iterator& operator++() { ++Pointer; CheckThis(); return *this; } FORCEINLINE constexpr FIterator& operator++() { ++Pointer; CheckThis(); return *this; }
FORCEINLINE constexpr Iterator& operator--() { --Pointer; CheckThis(); return *this; } FORCEINLINE constexpr FIterator& operator--() { --Pointer; CheckThis(); return *this; }
FORCEINLINE constexpr Iterator operator++(int) { Iterator Temp = *this; ++*this; return Temp; } FORCEINLINE constexpr FIterator operator++(int) { FIterator Temp = *this; ++*this; return Temp; }
FORCEINLINE constexpr Iterator operator--(int) { Iterator Temp = *this; --*this; return Temp; } FORCEINLINE constexpr FIterator operator--(int) { FIterator Temp = *this; --*this; return Temp; }
FORCEINLINE constexpr Iterator& operator+=(ptrdiff Offset) { Pointer += Offset; CheckThis(); return *this; } FORCEINLINE constexpr FIterator& operator+=(ptrdiff Offset) { Pointer += Offset; CheckThis(); return *this; }
FORCEINLINE constexpr Iterator& operator-=(ptrdiff Offset) { Pointer -= Offset; CheckThis(); return *this; } FORCEINLINE constexpr FIterator& operator-=(ptrdiff Offset) { Pointer -= Offset; CheckThis(); return *this; }
NODISCARD friend FORCEINLINE constexpr Iterator operator+(Iterator Iter, ptrdiff Offset) { Iterator Temp = Iter; Temp += Offset; return Temp; } NODISCARD friend FORCEINLINE constexpr FIterator operator+(FIterator Iter, ptrdiff Offset) { FIterator Temp = Iter; Temp += Offset; return Temp; }
NODISCARD friend FORCEINLINE constexpr Iterator operator+(ptrdiff Offset, Iterator Iter) { Iterator Temp = Iter; Temp += Offset; return Temp; } NODISCARD friend FORCEINLINE constexpr FIterator operator+(ptrdiff Offset, FIterator Iter) { FIterator Temp = Iter; Temp += Offset; return Temp; }
NODISCARD FORCEINLINE constexpr Iterator operator-(ptrdiff Offset) const { Iterator Temp = *this; Temp -= Offset; return Temp; } NODISCARD FORCEINLINE constexpr FIterator operator-(ptrdiff Offset) const { FIterator Temp = *this; Temp -= Offset; return Temp; }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const Iterator& LHS, const Iterator& RHS) { LHS.CheckThis(); RHS.CheckThis(); return LHS.Pointer - RHS.Pointer; } NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FIterator& LHS, const FIterator& RHS) { LHS.CheckThis(); RHS.CheckThis(); return LHS.Pointer - RHS.Pointer; }
private: private:
@ -345,11 +345,11 @@ public:
T* Pointer = nullptr; T* Pointer = nullptr;
# if DO_CHECK # if DO_CHECK
FORCEINLINE constexpr Iterator(const TArrayView* InContainer, T* InPointer) FORCEINLINE constexpr FIterator(const TArrayView* InContainer, T* InPointer)
: Owner(InContainer), Pointer(InPointer) : Owner(InContainer), Pointer(InPointer)
{ } { }
# else # else
FORCEINLINE constexpr Iterator(const TArrayView* InContainer, T* InPointer) FORCEINLINE constexpr FIterator(const TArrayView* InContainer, T* InPointer)
: Pointer(InPointer) : Pointer(InPointer)
{ } { }
# endif # endif
@ -367,7 +367,7 @@ public:
}; };
template <typename I, typename S> template <typename I, typename S>
TArrayView(I, S) -> TArrayView<TRemoveReference<TIteratorReferenceType<I>>>; TArrayView(I, S) -> TArrayView<TRemoveReference<TIteratorReference<I>>>;
template <typename T, size_t N> template <typename T, size_t N>
TArrayView(T(&)[N]) -> TArrayView<T, N>; TArrayView(T(&)[N]) -> TArrayView<T, N>;

View File

@ -1,16 +1,17 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Memory/Memory.h" #include "TypeTraits/TypeTraits.h"
#include "Memory/Allocator.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "Templates/TypeHash.h" #include "Templates/TypeHash.h"
#include "Templates/Noncopyable.h" #include "Templates/Noncopyable.h"
#include "TypeTraits/TypeTraits.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/Compare.h"
#include "Memory/MemoryOperator.h"
#include "Miscellaneous/Iterator.h"
#include "Miscellaneous/Container.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
@ -20,7 +21,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
template <CUnsignedIntegral InBlockType> requires (!CSameAs<InBlockType, bool>) template <CUnsignedIntegral InBlockType> requires (!CSameAs<InBlockType, bool>)
using TDefaultBitsetAllocator = TInlineAllocator<(40 - 3 * sizeof(size_t)) / sizeof(InBlockType)>; using TDefaultBitsetAllocator = TInlineAllocator<(40 - 3 * sizeof(size_t)) / sizeof(InBlockType)>;
template <CUnsignedIntegral InBlockType, CAllocator<InBlockType> Allocator = TDefaultBitsetAllocator<InBlockType>> requires (!CSameAs<InBlockType, bool>) template <CUnsignedIntegral InBlockType, CAllocator<InBlockType> Allocator = TDefaultBitsetAllocator<InBlockType>> requires (CAllocatableObject<InBlockType> && !CSameAs<InBlockType, bool>)
class TBitset class TBitset
{ {
private: private:
@ -30,23 +31,23 @@ private:
public: public:
using BlockType = InBlockType; using FBlockType = InBlockType;
using ElementType = bool; using FElementType = bool;
using AllocatorType = Allocator; using FAllocatorType = Allocator;
class Reference; class FReference;
using ConstReference = bool; using FConstReference = bool;
using Iterator = TIteratorImpl<false>; using FIterator = TIteratorImpl<false>;
using ConstIterator = TIteratorImpl<true >; using FConstIterator = TIteratorImpl<true >;
using ReverseIterator = TReverseIterator< Iterator>; using FReverseIterator = TReverseIterator< FIterator>;
using ConstReverseIterator = TReverseIterator<ConstIterator>; using FConstReverseIterator = TReverseIterator<FConstIterator>;
static_assert(CRandomAccessIterator< Iterator>); static_assert(CRandomAccessIterator< FIterator>);
static_assert(CRandomAccessIterator<ConstIterator>); static_assert(CRandomAccessIterator<FConstIterator>);
static constexpr size_t BlockWidth = sizeof(BlockType) * 8; static constexpr size_t BlockWidth = sizeof(FBlockType) * 8;
/** Default constructor. Constructs an empty bitset. */ /** Default constructor. Constructs an empty bitset. */
FORCEINLINE TBitset() : TBitset(0) { } FORCEINLINE TBitset() : TBitset(0) { }
@ -62,59 +63,63 @@ public:
/** Constructs a bitset from an integer. */ /** Constructs a bitset from an integer. */
TBitset(size_t InCount, uint64 InValue) : TBitset(InCount > 64 ? InCount : 64) TBitset(size_t InCount, uint64 InValue) : TBitset(InCount > 64 ? InCount : 64)
{ {
static_assert(sizeof(BlockType) <= sizeof(uint64), "The block width of TBitset is unexpected"); static_assert(sizeof(FBlockType) <= sizeof(uint64), "The block width of TBitset is unexpected");
if constexpr (sizeof(BlockType) == sizeof(uint8)) if constexpr (sizeof(FBlockType) == sizeof(uint8))
{ {
Impl.Pointer[0] = static_cast<BlockType>(InValue >> 0); Impl.Pointer[0] = static_cast<FBlockType>(InValue >> 0);
Impl.Pointer[1] = static_cast<BlockType>(InValue >> 8); Impl.Pointer[1] = static_cast<FBlockType>(InValue >> 8);
Impl.Pointer[2] = static_cast<BlockType>(InValue >> 16); Impl.Pointer[2] = static_cast<FBlockType>(InValue >> 16);
Impl.Pointer[3] = static_cast<BlockType>(InValue >> 24); Impl.Pointer[3] = static_cast<FBlockType>(InValue >> 24);
Impl.Pointer[4] = static_cast<BlockType>(InValue >> 32); Impl.Pointer[4] = static_cast<FBlockType>(InValue >> 32);
Impl.Pointer[5] = static_cast<BlockType>(InValue >> 40); Impl.Pointer[5] = static_cast<FBlockType>(InValue >> 40);
Impl.Pointer[6] = static_cast<BlockType>(InValue >> 48); Impl.Pointer[6] = static_cast<FBlockType>(InValue >> 48);
Impl.Pointer[7] = static_cast<BlockType>(InValue >> 56); Impl.Pointer[7] = static_cast<FBlockType>(InValue >> 56);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint16)) else if constexpr (sizeof(FBlockType) == sizeof(uint16))
{ {
Impl.Pointer[0] = static_cast<BlockType>(InValue >> 0); Impl.Pointer[0] = static_cast<FBlockType>(InValue >> 0);
Impl.Pointer[1] = static_cast<BlockType>(InValue >> 16); Impl.Pointer[1] = static_cast<FBlockType>(InValue >> 16);
Impl.Pointer[2] = static_cast<BlockType>(InValue >> 32); Impl.Pointer[2] = static_cast<FBlockType>(InValue >> 32);
Impl.Pointer[3] = static_cast<BlockType>(InValue >> 48); Impl.Pointer[3] = static_cast<FBlockType>(InValue >> 48);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint32)) else if constexpr (sizeof(FBlockType) == sizeof(uint32))
{ {
Impl.Pointer[0] = static_cast<BlockType>(InValue >> 0); Impl.Pointer[0] = static_cast<FBlockType>(InValue >> 0);
Impl.Pointer[1] = static_cast<BlockType>(InValue >> 32); Impl.Pointer[1] = static_cast<FBlockType>(InValue >> 32);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint64)) else if constexpr (sizeof(FBlockType) == sizeof(uint64))
{ {
Impl.Pointer[0] = static_cast<BlockType>(InValue >> 0); Impl.Pointer[0] = static_cast<FBlockType>(InValue >> 0);
} }
else check_no_entry(); else check_no_entry();
size_t BlockInteger = sizeof(uint64) / sizeof(BlockType); size_t BlockInteger = sizeof(uint64) / sizeof(FBlockType);
Memory::Memset(Impl.Pointer + BlockInteger, 0, (NumBlocks() - BlockInteger) * sizeof(BlockType)); Memory::Memset(Impl.Pointer + BlockInteger, 0, (NumBlocks() - BlockInteger) * sizeof(FBlockType));
Impl.BitsetNum = InCount; Impl.BitsetNum = InCount;
} }
/** Constructs the bitset with the bits of the range ['First', 'Last'). */ /** Constructs the bitset with the bits of the range ['First', 'Last'). */
template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<bool, TIteratorReferenceType<I>>) template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<bool, TIteratorReference<I>>)
TBitset(I First, S Last) TBitset(I First, S Last)
{ {
if constexpr (CForwardIterator<I>) if constexpr (CForwardIterator<I>)
{ {
if (CSizedSentinelFor<S, I>) { checkf(First <= Last, TEXT("Illegal range iterator. Please check First <= Last.")); } size_t Count = 0;
const size_t InCount = Iteration::Distance(First, Last); if constexpr (CSizedSentinelFor<S, I>)
{
checkf(First - Last <= 0, TEXT("Illegal range iterator. Please check First <= Last."));
new (this) TBitset(InCount); Count = Last - First;
}
else for (I Iter = First; Iter != Last; ++Iter) ++Count;
BlockType* CurrentBlock = Impl.Pointer - 1; new (this) TBitset(Count);
for (Reference Ref: *this) Ref = *First++; for (FReference Ref: *this) Ref = *First++;
} }
else else
{ {
@ -128,6 +133,10 @@ 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(Ranges::Begin(Range), Ranges::End(Range)) { }
/** Copy constructor. Constructs the bitset with the copy of the bits of 'InValue'. */ /** Copy constructor. Constructs the bitset with the copy of the bits of 'InValue'. */
FORCEINLINE TBitset(const TBitset& InValue) FORCEINLINE TBitset(const TBitset& InValue)
{ {
@ -135,7 +144,7 @@ public:
Impl.BlocksMax = Impl->CalculateSlackReserve(NumBlocks()); Impl.BlocksMax = Impl->CalculateSlackReserve(NumBlocks());
Impl.Pointer = Impl->Allocate(MaxBlocks()); Impl.Pointer = Impl->Allocate(MaxBlocks());
Memory::Memcpy(Impl.Pointer, InValue.Impl.Pointer, NumBlocks() * sizeof(BlockType)); Memory::Memcpy(Impl.Pointer, InValue.Impl.Pointer, NumBlocks() * sizeof(FBlockType));
} }
/** Move constructor. After the move, 'InValue' is guaranteed to be empty. */ /** Move constructor. After the move, 'InValue' is guaranteed to be empty. */
@ -157,12 +166,12 @@ public:
Impl.BlocksMax = Impl->CalculateSlackReserve(NumBlocks()); Impl.BlocksMax = Impl->CalculateSlackReserve(NumBlocks());
Impl.Pointer = Impl->Allocate(MaxBlocks()); Impl.Pointer = Impl->Allocate(MaxBlocks());
Memory::Memcpy(Impl.Pointer, InValue.Impl.Pointer, NumBlocks() * sizeof(BlockType)); Memory::Memcpy(Impl.Pointer, InValue.Impl.Pointer, NumBlocks() * sizeof(FBlockType));
} }
} }
/** Constructs the bitset with the bits of the initializer list. */ /** Constructs the bitset with the bits of the initializer list. */
FORCEINLINE TBitset(initializer_list<bool> IL) : TBitset(Iteration::Begin(IL), Iteration::End(IL)) { } FORCEINLINE TBitset(initializer_list<bool> IL) : TBitset(Ranges::Begin(IL), Ranges::End(IL)) { }
/** Destructs the bitset. The storage is deallocated. */ /** Destructs the bitset. The storage is deallocated. */
~TBitset() ~TBitset()
@ -188,7 +197,7 @@ public:
Impl.BlocksMax = NumToAllocate; Impl.BlocksMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(MaxBlocks()); Impl.Pointer = Impl->Allocate(MaxBlocks());
Memory::Memcpy(Impl.Pointer, InValue.Impl.Pointer, NumBlocks() * sizeof(BlockType)); Memory::Memcpy(Impl.Pointer, InValue.Impl.Pointer, NumBlocks() * sizeof(FBlockType));
return *this; return *this;
} }
@ -197,7 +206,7 @@ public:
Impl.BitsetNum = InValue.Num(); Impl.BitsetNum = InValue.Num();
Memory::Memcpy(Impl.Pointer, InValue.Impl.Pointer, NumBlocks() * sizeof(BlockType)); Memory::Memcpy(Impl.Pointer, InValue.Impl.Pointer, NumBlocks() * sizeof(FBlockType));
return *this; return *this;
} }
@ -230,9 +239,9 @@ public:
/** Replaces the bits with those identified by initializer list. */ /** Replaces the bits with those identified by initializer list. */
TBitset& operator=(initializer_list<bool> IL) TBitset& operator=(initializer_list<bool> IL)
{ {
auto First = Iteration::Begin(IL); auto First = Ranges::Begin(IL);
const size_t BlocksCount = (GetNum(IL) + BlockWidth - 1) / BlockWidth; const size_t BlocksCount = (Ranges::Num(IL) + BlockWidth - 1) / BlockWidth;
size_t NumToAllocate = BlocksCount; size_t NumToAllocate = BlocksCount;
@ -243,18 +252,18 @@ public:
{ {
Impl->Deallocate(Impl.Pointer); Impl->Deallocate(Impl.Pointer);
Impl.BitsetNum = GetNum(IL); Impl.BitsetNum = Ranges::Num(IL);
Impl.BlocksMax = NumToAllocate; Impl.BlocksMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(MaxBlocks()); Impl.Pointer = Impl->Allocate(MaxBlocks());
for (Reference Ref : *this) Ref = *First++; for (FReference Ref : *this) Ref = *First++;
return *this; return *this;
} }
Impl.BitsetNum = GetNum(IL); Impl.BitsetNum = Ranges::Num(IL);
for (Reference Ref : *this) Ref = *First++; for (FReference Ref : *this) Ref = *First++;
return *this; return *this;
} }
@ -271,7 +280,7 @@ public:
if (LHS.Impl.Pointer[Index] != RHS.Impl.Pointer[Index]) return false; if (LHS.Impl.Pointer[Index] != RHS.Impl.Pointer[Index]) return false;
} }
const BlockType LastBlockBitmask = LHS.Num() % BlockWidth != 0 ? (1ull << LHS.Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = LHS.Num() % BlockWidth != 0 ? (1ull << LHS.Num() % BlockWidth) - 1 : -1;
return (LHS.Impl.Pointer[LHS.NumBlocks() - 1] & LastBlockBitmask) == (RHS.Impl.Pointer[LHS.NumBlocks() - 1] & LastBlockBitmask); return (LHS.Impl.Pointer[LHS.NumBlocks() - 1] & LastBlockBitmask) == (RHS.Impl.Pointer[LHS.NumBlocks() - 1] & LastBlockBitmask);
} }
@ -301,7 +310,7 @@ public:
Impl.Pointer[Index] &= InValue.Impl.Pointer[Index]; Impl.Pointer[Index] &= InValue.Impl.Pointer[Index];
} }
const BlockType LastBlockBitmask = InValue.Num() % BlockWidth != 0 ? (1ull << InValue.Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = InValue.Num() % BlockWidth != 0 ? (1ull << InValue.Num() % BlockWidth) - 1 : -1;
Impl.Pointer[LastBlock] &= InValue.Impl.Pointer[LastBlock] & LastBlockBitmask; Impl.Pointer[LastBlock] &= InValue.Impl.Pointer[LastBlock] & LastBlockBitmask;
@ -339,7 +348,7 @@ public:
Impl.Pointer[Index] |= InValue.Impl.Pointer[Index]; Impl.Pointer[Index] |= InValue.Impl.Pointer[Index];
} }
const BlockType LastBlockBitmask = InValue.Num() % BlockWidth != 0 ? (1ull << InValue.Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = InValue.Num() % BlockWidth != 0 ? (1ull << InValue.Num() % BlockWidth) - 1 : -1;
Impl.Pointer[LastBlock] |= InValue.Impl.Pointer[LastBlock] & LastBlockBitmask; Impl.Pointer[LastBlock] |= InValue.Impl.Pointer[LastBlock] & LastBlockBitmask;
} }
@ -372,7 +381,7 @@ public:
Impl.Pointer[Index] ^= InValue.Impl.Pointer[Index]; Impl.Pointer[Index] ^= InValue.Impl.Pointer[Index];
} }
const BlockType LastBlockBitmask = InValue.Num() % BlockWidth != 0 ? (1ull << InValue.Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = InValue.Num() % BlockWidth != 0 ? (1ull << InValue.Num() % BlockWidth) - 1 : -1;
Impl.Pointer[LastBlock] ^= InValue.Impl.Pointer[LastBlock] & LastBlockBitmask; Impl.Pointer[LastBlock] ^= InValue.Impl.Pointer[LastBlock] & LastBlockBitmask;
} }
@ -473,7 +482,7 @@ public:
if (Impl.Pointer[Index] != -1) return false; if (Impl.Pointer[Index] != -1) return false;
} }
const BlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1;
return (Impl.Pointer[NumBlocks() - 1] | ~LastBlockBitmask) == -1; return (Impl.Pointer[NumBlocks() - 1] | ~LastBlockBitmask) == -1;
} }
@ -488,7 +497,7 @@ public:
if (Impl.Pointer[Index] != 0) return true; if (Impl.Pointer[Index] != 0) return true;
} }
const BlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1;
return (Impl.Pointer[NumBlocks() - 1] & LastBlockBitmask) != 0; return (Impl.Pointer[NumBlocks() - 1] & LastBlockBitmask) != 0;
} }
@ -503,24 +512,24 @@ public:
size_t Result = 0; size_t Result = 0;
constexpr auto BlockCount = [](BlockType Block) constexpr auto BlockCount = [](FBlockType Block)
{ {
static_assert(sizeof(BlockType) <= sizeof(uint64), "The block width of TBitset is unexpected"); static_assert(sizeof(FBlockType) <= sizeof(uint64), "The block width of TBitset is unexpected");
if constexpr (sizeof(BlockType) == sizeof(uint8)) if constexpr (sizeof(FBlockType) == sizeof(uint8))
{ {
Block = (Block & 0x55ull) + ((Block >> 1) & 0x55ull); Block = (Block & 0x55ull) + ((Block >> 1) & 0x55ull);
Block = (Block & 0x33ull) + ((Block >> 2) & 0x33ull); Block = (Block & 0x33ull) + ((Block >> 2) & 0x33ull);
Block = (Block & 0x0Full) + ((Block >> 4) & 0x0Full); Block = (Block & 0x0Full) + ((Block >> 4) & 0x0Full);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint16)) else if constexpr (sizeof(FBlockType) == sizeof(uint16))
{ {
Block = (Block & 0x5555ull) + ((Block >> 1) & 0x5555ull); Block = (Block & 0x5555ull) + ((Block >> 1) & 0x5555ull);
Block = (Block & 0x3333ull) + ((Block >> 2) & 0x3333ull); Block = (Block & 0x3333ull) + ((Block >> 2) & 0x3333ull);
Block = (Block & 0x0F0Full) + ((Block >> 4) & 0x0F0Full); Block = (Block & 0x0F0Full) + ((Block >> 4) & 0x0F0Full);
Block = (Block & 0x00FFull) + ((Block >> 8) & 0x00FFull); Block = (Block & 0x00FFull) + ((Block >> 8) & 0x00FFull);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint32)) else if constexpr (sizeof(FBlockType) == sizeof(uint32))
{ {
Block = (Block & 0x55555555ull) + ((Block >> 1) & 0x55555555ull); Block = (Block & 0x55555555ull) + ((Block >> 1) & 0x55555555ull);
Block = (Block & 0x33333333ull) + ((Block >> 2) & 0x33333333ull); Block = (Block & 0x33333333ull) + ((Block >> 2) & 0x33333333ull);
@ -528,7 +537,7 @@ public:
Block = (Block & 0x00FF00FFull) + ((Block >> 8) & 0x00FF00FFull); Block = (Block & 0x00FF00FFull) + ((Block >> 8) & 0x00FF00FFull);
Block = (Block & 0x0000FFFFull) + ((Block >> 16) & 0x0000FFFFull); Block = (Block & 0x0000FFFFull) + ((Block >> 16) & 0x0000FFFFull);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint64)) else if constexpr (sizeof(FBlockType) == sizeof(uint64))
{ {
Block = (Block & 0x5555555555555555ull) + ((Block >> 1) & 0x5555555555555555ull); Block = (Block & 0x5555555555555555ull) + ((Block >> 1) & 0x5555555555555555ull);
Block = (Block & 0x3333333333333333ull) + ((Block >> 2) & 0x3333333333333333ull); Block = (Block & 0x3333333333333333ull) + ((Block >> 2) & 0x3333333333333333ull);
@ -547,7 +556,7 @@ public:
Result += BlockCount(Impl.Pointer[Index]); Result += BlockCount(Impl.Pointer[Index]);
} }
const BlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1;
Result += BlockCount(Impl.Pointer[NumBlocks() - 1] & LastBlockBitmask); Result += BlockCount(Impl.Pointer[NumBlocks() - 1] & LastBlockBitmask);
@ -557,7 +566,7 @@ public:
/** Sets all bits to true. */ /** Sets all bits to true. */
TBitset& Set(bool InValue = true) TBitset& Set(bool InValue = true)
{ {
Memory::Memset(Impl.Pointer, static_cast<uint8>(InValue ? -1 : 0), NumBlocks() * sizeof(BlockType)); Memory::Memset(Impl.Pointer, static_cast<uint8>(InValue ? -1 : 0), NumBlocks() * sizeof(FBlockType));
return *this; return *this;
} }
@ -591,17 +600,17 @@ public:
checkf(Impl.Pointer[Index] != 0, TEXT("The bitset can not be represented in uint64. Please check Num().")); checkf(Impl.Pointer[Index] != 0, TEXT("The bitset can not be represented in uint64. Please check Num()."));
} }
const BlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1;
const BlockType LastBlock = Impl.Pointer[NumBlocks() - 1] & LastBlockBitmask; const FBlockType LastBlock = Impl.Pointer[NumBlocks() - 1] & LastBlockBitmask;
checkf(LastBlock != 0, TEXT("The bitset can not be represented in uint64. Please check Num().")); checkf(LastBlock != 0, TEXT("The bitset can not be represented in uint64. Please check Num()."));
} }
uint64 Result = 0; uint64 Result = 0;
static_assert(sizeof(BlockType) <= sizeof(uint64), "The block width of TBitset is unexpected"); static_assert(sizeof(FBlockType) <= sizeof(uint64), "The block width of TBitset is unexpected");
if constexpr (sizeof(BlockType) == sizeof(uint8)) if constexpr (sizeof(FBlockType) == sizeof(uint8))
{ {
Result |= static_cast<uint64>(Impl.Pointer[0]) << 0; Result |= static_cast<uint64>(Impl.Pointer[0]) << 0;
Result |= static_cast<uint64>(Impl.Pointer[1]) << 8; Result |= static_cast<uint64>(Impl.Pointer[1]) << 8;
@ -612,19 +621,19 @@ public:
Result |= static_cast<uint64>(Impl.Pointer[6]) << 48; Result |= static_cast<uint64>(Impl.Pointer[6]) << 48;
Result |= static_cast<uint64>(Impl.Pointer[7]) << 56; Result |= static_cast<uint64>(Impl.Pointer[7]) << 56;
} }
else if constexpr (sizeof(BlockType) == sizeof(uint16)) else if constexpr (sizeof(FBlockType) == sizeof(uint16))
{ {
Result |= static_cast<uint64>(Impl.Pointer[0]) << 0; Result |= static_cast<uint64>(Impl.Pointer[0]) << 0;
Result |= static_cast<uint64>(Impl.Pointer[1]) << 16; Result |= static_cast<uint64>(Impl.Pointer[1]) << 16;
Result |= static_cast<uint64>(Impl.Pointer[2]) << 32; Result |= static_cast<uint64>(Impl.Pointer[2]) << 32;
Result |= static_cast<uint64>(Impl.Pointer[3]) << 48; Result |= static_cast<uint64>(Impl.Pointer[3]) << 48;
} }
else if constexpr (sizeof(BlockType) == sizeof(uint32)) else if constexpr (sizeof(FBlockType) == sizeof(uint32))
{ {
Result |= static_cast<uint64>(Impl.Pointer[0]) << 0; Result |= static_cast<uint64>(Impl.Pointer[0]) << 0;
Result |= static_cast<uint64>(Impl.Pointer[1]) << 32; Result |= static_cast<uint64>(Impl.Pointer[1]) << 32;
} }
else if constexpr (sizeof(BlockType) == sizeof(uint64)) else if constexpr (sizeof(FBlockType) == sizeof(uint64))
{ {
Result |= static_cast<uint64>(Impl.Pointer[0]) << 0; Result |= static_cast<uint64>(Impl.Pointer[0]) << 0;
} }
@ -661,7 +670,7 @@ public:
if (NumToAllocate != MaxBlocks()) if (NumToAllocate != MaxBlocks())
{ {
BlockType* OldAllocation = Impl.Pointer; FBlockType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = NumBlocks(); const size_t NumToDestruct = NumBlocks();
Impl.BitsetNum = InCount; Impl.BitsetNum = InCount;
@ -670,11 +679,11 @@ public:
if (NumToDestruct <= Num()) if (NumToDestruct <= Num())
{ {
Memory::Memcpy(Impl.Pointer, OldAllocation, NumToDestruct * sizeof(BlockType)); Memory::Memcpy(Impl.Pointer, OldAllocation, NumToDestruct * sizeof(FBlockType));
} }
else else
{ {
Memory::Memcpy(Impl.Pointer, OldAllocation, BlocksCount * sizeof(BlockType)); Memory::Memcpy(Impl.Pointer, OldAllocation, BlocksCount * sizeof(FBlockType));
} }
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
@ -697,12 +706,12 @@ public:
NumToAllocate = NumToAllocate > MaxBlocks() ? Impl->CalculateSlackGrow(BlocksCount, MaxBlocks()) : NumToAllocate; NumToAllocate = NumToAllocate > MaxBlocks() ? Impl->CalculateSlackGrow(BlocksCount, MaxBlocks()) : NumToAllocate;
NumToAllocate = NumToAllocate < MaxBlocks() ? (bAllowShrinking ? Impl->CalculateSlackShrink(BlocksCount, MaxBlocks()) : MaxBlocks()) : NumToAllocate; NumToAllocate = NumToAllocate < MaxBlocks() ? (bAllowShrinking ? Impl->CalculateSlackShrink(BlocksCount, MaxBlocks()) : MaxBlocks()) : NumToAllocate;
const BlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1;
const BlockType BlocksValueToSet = static_cast<BlockType>(InValue ? -1 : 0); const FBlockType BlocksValueToSet = static_cast<FBlockType>(InValue ? -1 : 0);
if (NumToAllocate != MaxBlocks()) if (NumToAllocate != MaxBlocks())
{ {
BlockType* OldAllocation = Impl.Pointer; FBlockType* OldAllocation = Impl.Pointer;
const size_t NumToDestruct = NumBlocks(); const size_t NumToDestruct = NumBlocks();
Impl.BitsetNum = InCount; Impl.BitsetNum = InCount;
@ -713,16 +722,16 @@ public:
{ {
if (NumToDestruct != 0) if (NumToDestruct != 0)
{ {
Memory::Memcpy(Impl.Pointer, OldAllocation, (NumToDestruct - 1) * sizeof(BlockType)); Memory::Memcpy(Impl.Pointer, OldAllocation, (NumToDestruct - 1) * sizeof(FBlockType));
Impl.Pointer[NumToDestruct - 1] = OldAllocation[NumToDestruct - 1] & LastBlockBitmask | BlocksValueToSet & ~LastBlockBitmask; Impl.Pointer[NumToDestruct - 1] = OldAllocation[NumToDestruct - 1] & LastBlockBitmask | BlocksValueToSet & ~LastBlockBitmask;
} }
Memory::Memset(Impl.Pointer + NumToDestruct, static_cast<uint8>(BlocksValueToSet), (BlocksCount - NumToDestruct) * sizeof(BlockType)); Memory::Memset(Impl.Pointer + NumToDestruct, static_cast<uint8>(BlocksValueToSet), (BlocksCount - NumToDestruct) * sizeof(FBlockType));
} }
else else
{ {
Memory::Memcpy(Impl.Pointer, OldAllocation, BlocksCount * sizeof(BlockType)); Memory::Memcpy(Impl.Pointer, OldAllocation, BlocksCount * sizeof(FBlockType));
} }
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
@ -739,7 +748,7 @@ public:
Impl.Pointer[NumBlocks() - 1] = Impl.Pointer[NumBlocks() - 1] & LastBlockBitmask | BlocksValueToSet & ~LastBlockBitmask; Impl.Pointer[NumBlocks() - 1] = Impl.Pointer[NumBlocks() - 1] & LastBlockBitmask | BlocksValueToSet & ~LastBlockBitmask;
} }
Memory::Memset(Impl.Pointer + NumBlocks(), static_cast<uint8>(BlocksValueToSet), (BlocksCount - NumBlocks()) * sizeof(BlockType)); Memory::Memset(Impl.Pointer + NumBlocks(), static_cast<uint8>(BlocksValueToSet), (BlocksCount - NumBlocks()) * sizeof(FBlockType));
} }
Impl.BitsetNum = InCount; Impl.BitsetNum = InCount;
@ -753,14 +762,14 @@ public:
const size_t BlocksCount = (InCount + BlockWidth - 1) / BlockWidth; const size_t BlocksCount = (InCount + BlockWidth - 1) / BlockWidth;
const size_t NumToAllocate = Impl->CalculateSlackReserve(BlocksCount); const size_t NumToAllocate = Impl->CalculateSlackReserve(BlocksCount);
BlockType* OldAllocation = Impl.Pointer; FBlockType* OldAllocation = Impl.Pointer;
check(NumToAllocate > MaxBlocks()); check(NumToAllocate > MaxBlocks());
Impl.BlocksMax = NumToAllocate; Impl.BlocksMax = NumToAllocate;
Impl.Pointer = Impl->Allocate(MaxBlocks()); Impl.Pointer = Impl->Allocate(MaxBlocks());
Memory::Memcpy(Impl.Pointer, OldAllocation, NumBlocks() * sizeof(BlockType)); Memory::Memcpy(Impl.Pointer, OldAllocation, NumBlocks() * sizeof(FBlockType));
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
} }
@ -774,31 +783,31 @@ public:
if (NumToAllocate == MaxBlocks()) return; if (NumToAllocate == MaxBlocks()) return;
BlockType* OldAllocation = Impl.Pointer; FBlockType* OldAllocation = Impl.Pointer;
Impl.BitsetNum = NumToAllocate * BlockWidth; Impl.BitsetNum = NumToAllocate * BlockWidth;
Impl.Pointer = Impl->Allocate(MaxBlocks()); Impl.Pointer = Impl->Allocate(MaxBlocks());
Memory::Memcpy(Impl.Pointer, OldAllocation, NumBlocks() * sizeof(BlockType)); Memory::Memcpy(Impl.Pointer, OldAllocation, NumBlocks() * sizeof(FBlockType));
Impl->Deallocate(OldAllocation); Impl->Deallocate(OldAllocation);
} }
/** @return The pointer to the underlying element storage. */ /** @return The pointer to the underlying element storage. */
NODISCARD FORCEINLINE BlockType* GetData() { return Impl.Pointer; } NODISCARD FORCEINLINE FBlockType* GetData() { return Impl.Pointer; }
NODISCARD FORCEINLINE const BlockType* GetData() const { return Impl.Pointer; } NODISCARD FORCEINLINE const FBlockType* GetData() const { return Impl.Pointer; }
/** @return The iterator to the first or end bit. */ /** @return The iterator to the first or end bit. */
NODISCARD FORCEINLINE Iterator Begin() { return Iterator(this, Impl.Pointer, 0); } NODISCARD FORCEINLINE FIterator Begin() { return FIterator(this, Impl.Pointer, 0); }
NODISCARD FORCEINLINE ConstIterator Begin() const { return ConstIterator(this, Impl.Pointer, 0); } NODISCARD FORCEINLINE FConstIterator Begin() const { return FConstIterator(this, Impl.Pointer, 0); }
NODISCARD FORCEINLINE Iterator End() { return Iterator(this, Impl.Pointer, Num()); } NODISCARD FORCEINLINE FIterator End() { return FIterator(this, Impl.Pointer, Num()); }
NODISCARD FORCEINLINE ConstIterator End() const { return ConstIterator(this, Impl.Pointer, Num()); } NODISCARD FORCEINLINE FConstIterator End() const { return FConstIterator(this, Impl.Pointer, Num()); }
/** @return The reverse iterator to the first or end bit. */ /** @return The reverse iterator to the first or end bit. */
NODISCARD FORCEINLINE ReverseIterator RBegin() { return ReverseIterator(End()); } NODISCARD FORCEINLINE FReverseIterator RBegin() { return FReverseIterator(End()); }
NODISCARD FORCEINLINE ConstReverseIterator RBegin() const { return ConstReverseIterator(End()); } NODISCARD FORCEINLINE FConstReverseIterator RBegin() const { return FConstReverseIterator(End()); }
NODISCARD FORCEINLINE ReverseIterator REnd() { return ReverseIterator(Begin()); } NODISCARD FORCEINLINE FReverseIterator REnd() { return FReverseIterator(Begin()); }
NODISCARD FORCEINLINE ConstReverseIterator REnd() const { return ConstReverseIterator(Begin()); } NODISCARD FORCEINLINE FConstReverseIterator REnd() const { return FConstReverseIterator(Begin()); }
/** @return The number of bits in the bitset. */ /** @return The number of bits in the bitset. */
NODISCARD FORCEINLINE size_t Num() const { return Impl.BitsetNum; } NODISCARD FORCEINLINE size_t Num() const { return Impl.BitsetNum; }
@ -816,17 +825,17 @@ public:
NODISCARD FORCEINLINE bool IsEmpty() const { return Num() == 0; } NODISCARD FORCEINLINE bool IsEmpty() const { return Num() == 0; }
/** @return true if the iterator is valid, false otherwise. */ /** @return true if the iterator is valid, false otherwise. */
NODISCARD FORCEINLINE bool IsValidIterator(ConstIterator Iter) const { return Begin() <= Iter && Iter <= End(); } NODISCARD FORCEINLINE bool IsValidIterator(FConstIterator Iter) const { return Begin() <= Iter && Iter <= End(); }
/** @return The reference to the requested bit. */ /** @return The reference to the requested bit. */
NODISCARD FORCEINLINE Reference operator[](size_t Index) { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return *(Begin() + Index); } NODISCARD FORCEINLINE FReference operator[](size_t Index) { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return *(Begin() + Index); }
NODISCARD FORCEINLINE ConstReference operator[](size_t Index) const { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return *(Begin() + Index); } NODISCARD FORCEINLINE FConstReference operator[](size_t Index) const { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return *(Begin() + Index); }
/** @return The reference to the first or last bit. */ /** @return The reference to the first or last bit. */
NODISCARD FORCEINLINE Reference Front() { return *Begin(); } NODISCARD FORCEINLINE FReference Front() { return *Begin(); }
NODISCARD FORCEINLINE ConstReference Front() const { return *Begin(); } NODISCARD FORCEINLINE FConstReference Front() const { return *Begin(); }
NODISCARD FORCEINLINE Reference Back() { return *(End() - 1); } NODISCARD FORCEINLINE FReference Back() { return *(End() - 1); }
NODISCARD FORCEINLINE ConstReference Back() const { return *(End() - 1); } NODISCARD FORCEINLINE FConstReference Back() const { return *(End() - 1); }
/** Erases all bits from the bitset. After this call, Num() returns zero. */ /** Erases all bits from the bitset. After this call, Num() returns zero. */
void Reset(bool bAllowShrinking = true) void Reset(bool bAllowShrinking = true)
@ -859,7 +868,7 @@ public:
Result = HashCombine(Result, GetTypeHash(A.Impl.Pointer[Index])); Result = HashCombine(Result, GetTypeHash(A.Impl.Pointer[Index]));
} }
const BlockType LastBlockBitmask = A.Num() % BlockWidth != 0 ? (1ull << A.Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = A.Num() % BlockWidth != 0 ? (1ull << A.Num() % BlockWidth) - 1 : -1;
return HashCombine(Result, GetTypeHash(A.Impl.Pointer[A.NumBlocks() - 1] & LastBlockBitmask)); return HashCombine(Result, GetTypeHash(A.Impl.Pointer[A.NumBlocks() - 1] & LastBlockBitmask));
} }
@ -889,27 +898,27 @@ public:
private: private:
ALLOCATOR_WRAPPER_BEGIN(AllocatorType, BlockType, Impl) ALLOCATOR_WRAPPER_BEGIN(FAllocatorType, FBlockType, Impl)
{ {
size_t BitsetNum; size_t BitsetNum;
size_t BlocksMax; size_t BlocksMax;
BlockType* Pointer; FBlockType* Pointer;
} }
ALLOCATOR_WRAPPER_END(AllocatorType, BlockType, Impl) ALLOCATOR_WRAPPER_END(FAllocatorType, FBlockType, Impl)
public: public:
class Reference final : private FSingleton class FReference final : private FSingleton
{ {
public: public:
FORCEINLINE Reference& operator=(bool InValue) { Data = (Data & ~Mask) | (InValue ? Mask : 0); return *this; } FORCEINLINE FReference& operator=(bool InValue) { Data = (Data & ~Mask) | (InValue ? Mask : 0); return *this; }
FORCEINLINE Reference& operator=(const Reference& InValue) { *this = static_cast<bool>(InValue); return *this; } FORCEINLINE FReference& operator=(const FReference& InValue) { *this = static_cast<bool>(InValue); return *this; }
FORCEINLINE Reference& operator&=(bool InValue) { Data &= InValue ? -1 : ~Mask; return *this; } FORCEINLINE FReference& operator&=(bool InValue) { Data &= InValue ? -1 : ~Mask; return *this; }
FORCEINLINE Reference& operator|=(bool InValue) { Data |= InValue ? Mask : 0; return *this; } FORCEINLINE FReference& operator|=(bool InValue) { Data |= InValue ? Mask : 0; return *this; }
FORCEINLINE Reference& operator^=(bool InValue) { *this = InValue ^ *this; return *this; } FORCEINLINE FReference& operator^=(bool InValue) { *this = InValue ^ *this; return *this; }
FORCEINLINE bool operator~() const { return !*this; } FORCEINLINE bool operator~() const { return !*this; }
@ -917,14 +926,14 @@ public:
private: private:
FORCEINLINE Reference(BlockType& InData, BlockType InMask) FORCEINLINE FReference(FBlockType& InData, FBlockType InMask)
: Data(InData), Mask(InMask) : Data(InData), Mask(InMask)
{ } { }
BlockType& Data; FBlockType& Data;
BlockType Mask; FBlockType Mask;
friend Iterator; friend FIterator;
}; };
@ -935,7 +944,7 @@ private:
{ {
public: public:
using ElementType = bool; using FElementType = bool;
FORCEINLINE TIteratorImpl() = default; FORCEINLINE TIteratorImpl() = default;
@ -958,8 +967,8 @@ private:
NODISCARD friend FORCEINLINE strong_ordering operator<=>(const TIteratorImpl& LHS, const TIteratorImpl& RHS) { check(LHS.Pointer == RHS.Pointer); return LHS.BitOffset <=> RHS.BitOffset; } NODISCARD friend FORCEINLINE strong_ordering operator<=>(const TIteratorImpl& LHS, const TIteratorImpl& RHS) { check(LHS.Pointer == RHS.Pointer); return LHS.BitOffset <=> RHS.BitOffset; }
NODISCARD FORCEINLINE Reference operator*() const requires (!bConst) { CheckThis(true); return Reference(*(Pointer + BitOffset / BlockWidth), 1ull << BitOffset % BlockWidth); } NODISCARD FORCEINLINE FReference operator*() const requires (!bConst) { CheckThis(true); return FReference(*(Pointer + BitOffset / BlockWidth), 1ull << BitOffset % BlockWidth); }
NODISCARD FORCEINLINE ConstReference operator*() const requires ( bConst) { CheckThis(true); return (*(Pointer + BitOffset / BlockWidth) & (1ull << BitOffset % BlockWidth)); } NODISCARD FORCEINLINE FConstReference operator*() const requires ( bConst) { CheckThis(true); return (*(Pointer + BitOffset / BlockWidth) & (1ull << BitOffset % BlockWidth)); }
NODISCARD FORCEINLINE auto operator[](ptrdiff Index) const { TIteratorImpl Temp = *this + Index; return *Temp; } NODISCARD FORCEINLINE auto operator[](ptrdiff Index) const { TIteratorImpl Temp = *this + Index; return *Temp; }
@ -985,17 +994,17 @@ private:
const TBitset* Owner = nullptr; const TBitset* Owner = nullptr;
# endif # endif
using BlockPtr = TConditional<bConst, const BlockType*, BlockType*>; using FBlockPtr = TConditional<bConst, const FBlockType*, FBlockType*>;
BlockPtr Pointer = nullptr; FBlockPtr Pointer = nullptr;
size_t BitOffset = 0; size_t BitOffset = 0;
# if DO_CHECK # if DO_CHECK
FORCEINLINE TIteratorImpl(const TBitset* InContainer, BlockPtr InPointer, size_t Offset) FORCEINLINE TIteratorImpl(const TBitset* InContainer, FBlockPtr InPointer, size_t Offset)
: Owner(InContainer), Pointer(InPointer), BitOffset(Offset) : Owner(InContainer), Pointer(InPointer), BitOffset(Offset)
{ } { }
# else # else
FORCEINLINE TIteratorImpl(const TBitset* InContainer, BlockPtr InPointer, size_t Offset) FORCEINLINE TIteratorImpl(const TBitset* InContainer, FBlockPtr InPointer, size_t Offset)
: Pointer(InPointer), BitOffset(Offset) : Pointer(InPointer), BitOffset(Offset)
{ } { }
# endif # endif

View File

@ -1,16 +1,19 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Memory/Allocator.h" #include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "Templates/TypeHash.h" #include "Templates/TypeHash.h"
#include "TypeTraits/TypeTraits.h" #include "Memory/Allocators.h"
#include "Miscellaneous/Compare.h"
#include "Memory/MemoryOperator.h" #include "Memory/MemoryOperator.h"
#include "Miscellaneous/Iterator.h" #include "Iterators/Utility.h"
#include "Miscellaneous/Container.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" #include "Miscellaneous/AssertionMacros.h"
#include "Miscellaneous/ConstantIterator.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Redcraft)
@ -28,20 +31,20 @@ private:
public: public:
using ElementType = T; using FElementType = T;
using AllocatorType = Allocator; using FAllocatorType = Allocator;
using Reference = T&; using FReference = T&;
using ConstReference = const T&; using FConstReference = const T&;
using Iterator = TIteratorImpl<false>; using FIterator = TIteratorImpl<false>;
using ConstIterator = TIteratorImpl<true >; using FConstIterator = TIteratorImpl<true >;
using ReverseIterator = TReverseIterator< Iterator>; using FReverseIterator = TReverseIterator< FIterator>;
using ConstReverseIterator = TReverseIterator<ConstIterator>; using FConstReverseIterator = TReverseIterator<FConstIterator>;
static_assert(CBidirectionalIterator< Iterator>); static_assert(CBidirectionalIterator< FIterator>);
static_assert(CBidirectionalIterator<ConstIterator>); static_assert(CBidirectionalIterator<FConstIterator>);
/** Default constructor. Constructs an empty container with a default-constructed allocator. */ /** Default constructor. Constructs an empty container with a default-constructed allocator. */
TList() TList()
@ -54,7 +57,7 @@ public:
} }
/** Constructs the container with 'Count' default instances of T. */ /** Constructs the container with 'Count' default instances of T. */
explicit TList(size_t Count) requires (CDefaultConstructible<ElementType>) : TList() explicit TList(size_t Count) requires (CDefaultConstructible<FElementType>) : TList()
{ {
FNode* EndNode = Impl.HeadNode->PrevNode; FNode* EndNode = Impl.HeadNode->PrevNode;
@ -75,12 +78,12 @@ public:
} }
/** Constructs the container with 'Count' copies of elements with 'InValue'. */ /** Constructs the container with 'Count' copies of elements with 'InValue'. */
TList(size_t Count, const ElementType& InValue) requires (CCopyable<ElementType>) TList(size_t Count, const FElementType& InValue) requires (CCopyable<FElementType>)
: TList(MakeCountedConstantIterator(InValue, Count), DefaultSentinel) : TList(Ranges::Repeat(InValue, Count))
{ } { }
/** Constructs the container with the contents of the range ['First', 'Last'). */ /** Constructs the container with the contents of the range ['First', 'Last'). */
template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<ElementType, TIteratorReferenceType<I>>) template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<FElementType, TIteratorReference<I>>)
TList(I First, S Last) : TList() TList(I First, S Last) : TList()
{ {
FNode* EndNode = Impl.HeadNode->PrevNode; FNode* EndNode = Impl.HeadNode->PrevNode;
@ -101,14 +104,18 @@ public:
Impl.HeadNode->PrevNode = EndNode; Impl.HeadNode->PrevNode = EndNode;
} }
/** 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(Ranges::Begin(Range), Ranges::End(Range)) { }
/** Copy constructor. Constructs the container with the copy of the contents of 'InValue'. */ /** Copy constructor. Constructs the container with the copy of the contents of 'InValue'. */
FORCEINLINE TList(const TList& InValue) requires (CCopyConstructible<ElementType>) : TList(InValue.Begin(), InValue.End()) { } FORCEINLINE TList(const TList& InValue) requires (CCopyConstructible<FElementType>) : TList(InValue.Begin(), InValue.End()) { }
/** Move constructor. After the move, 'InValue' is guaranteed to be empty. */ /** Move constructor. After the move, 'InValue' is guaranteed to be empty. */
FORCEINLINE TList(TList&& InValue) : TList() { Swap(*this, InValue); } FORCEINLINE TList(TList&& InValue) : TList() { Swap(*this, InValue); }
/** Constructs the container with the contents of the initializer list. */ /** Constructs the container with the contents of the initializer list. */
FORCEINLINE TList(initializer_list<ElementType> IL) requires (CCopyConstructible<ElementType>) : TList(Iteration::Begin(IL), Iteration::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. */ /** Destructs the list. The destructors of the elements are called and the used storage is deallocated. */
~TList() ~TList()
@ -129,12 +136,12 @@ public:
} }
/** Copy assignment operator. Replaces the contents with a copy of the contents of 'InValue'. */ /** Copy assignment operator. Replaces the contents with a copy of the contents of 'InValue'. */
TList& operator=(const TList& InValue) requires (CCopyable<ElementType>) TList& operator=(const TList& InValue) requires (CCopyable<FElementType>)
{ {
if (&InValue == this) UNLIKELY return *this; if (&InValue == this) UNLIKELY return *this;
Iterator ThisIter = Begin(); FIterator ThisIter = Begin();
ConstIterator OtherIter = InValue.Begin(); FConstIterator OtherIter = InValue.Begin();
while (ThisIter != End() && OtherIter != InValue.End()) while (ThisIter != End() && OtherIter != InValue.End())
{ {
@ -166,12 +173,12 @@ public:
FORCEINLINE TList& operator=(TList&& InValue) { Swap(*this, InValue); InValue.Reset(); return *this; } FORCEINLINE TList& operator=(TList&& InValue) { Swap(*this, InValue); InValue.Reset(); return *this; }
/** Replaces the contents with those identified by initializer list. */ /** Replaces the contents with those identified by initializer list. */
TList& operator=(initializer_list<ElementType> IL) requires (CCopyable<ElementType>) TList& operator=(initializer_list<FElementType> IL) requires (CCopyable<FElementType>)
{ {
Iterator ThisIter = Begin(); FIterator ThisIter = Begin();
const ElementType* OtherIter = Iteration::Begin(IL); const FElementType* OtherIter = Ranges::Begin(IL);
while (ThisIter != End() && OtherIter != Iteration::End(IL)) while (ThisIter != End() && OtherIter != Ranges::End(IL))
{ {
*ThisIter = *OtherIter; *ThisIter = *OtherIter;
@ -181,29 +188,29 @@ public:
if (ThisIter == End()) if (ThisIter == End())
{ {
while (OtherIter != Iteration::End(IL)) while (OtherIter != Ranges::End(IL))
{ {
EmplaceBack(*OtherIter); EmplaceBack(*OtherIter);
++OtherIter; ++OtherIter;
} }
} }
else if (OtherIter == Iteration::End(IL)) else if (OtherIter == Ranges::End(IL))
{ {
Erase(ThisIter, End()); Erase(ThisIter, End());
} }
Impl.ListNum = GetNum(IL); Impl.ListNum = Ranges::Num(IL);
return *this; return *this;
} }
/** Compares the contents of two lists. */ /** Compares the contents of two lists. */
NODISCARD friend bool operator==(const TList& LHS, const TList& RHS) requires (CWeaklyEqualityComparable<ElementType>) NODISCARD friend bool operator==(const TList& LHS, const TList& RHS) requires (CWeaklyEqualityComparable<FElementType>)
{ {
if (LHS.Num() != RHS.Num()) return false; if (LHS.Num() != RHS.Num()) return false;
ConstIterator LHSIter = LHS.Begin(); FConstIterator LHSIter = LHS.Begin();
ConstIterator RHSIter = RHS.Begin(); FConstIterator RHSIter = RHS.Begin();
while (LHSIter != LHS.End()) while (LHSIter != LHS.End())
{ {
@ -219,10 +226,10 @@ public:
} }
/** Compares the contents of 'LHS' and 'RHS' lexicographically. */ /** Compares the contents of 'LHS' and 'RHS' lexicographically. */
NODISCARD friend auto operator<=>(const TList& LHS, const TList& RHS) requires (CSynthThreeWayComparable<ElementType>) NODISCARD friend auto operator<=>(const TList& LHS, const TList& RHS) requires (CSynthThreeWayComparable<FElementType>)
{ {
ConstIterator LHSIter = LHS.Begin(); FConstIterator LHSIter = LHS.Begin();
ConstIterator RHSIter = RHS.Begin(); FConstIterator RHSIter = RHS.Begin();
while (LHSIter != LHS.End() && RHSIter != RHS.End()) while (LHSIter != LHS.End() && RHSIter != RHS.End())
{ {
@ -236,22 +243,22 @@ public:
} }
/** Inserts 'InValue' before 'Iter' in the container. */ /** Inserts 'InValue' before 'Iter' in the container. */
FORCEINLINE Iterator Insert(ConstIterator Iter, const ElementType& InValue) requires (CCopyConstructible<ElementType>) { return Emplace(Iter, InValue); } FORCEINLINE FIterator Insert(FConstIterator Iter, const FElementType& InValue) requires (CCopyConstructible<FElementType>) { return Emplace(Iter, InValue); }
/** Inserts 'InValue' before 'Iter' in the container. */ /** Inserts 'InValue' before 'Iter' in the container. */
FORCEINLINE Iterator Insert(ConstIterator Iter, ElementType&& InValue) requires (CMoveConstructible<ElementType>) { return Emplace(Iter, MoveTemp(InValue)); } FORCEINLINE FIterator Insert(FConstIterator Iter, FElementType&& InValue) requires (CMoveConstructible<FElementType>) { return Emplace(Iter, MoveTemp(InValue)); }
/** Inserts 'Count' copies of the 'InValue' before 'Iter' in the container. */ /** Inserts 'Count' copies of the 'InValue' before 'Iter' in the container. */
Iterator Insert(ConstIterator Iter, size_t Count, const ElementType& InValue) requires (CCopyConstructible<ElementType>) FIterator Insert(FConstIterator Iter, size_t Count, const FElementType& InValue) requires (CCopyConstructible<FElementType>)
{ {
return Insert(Iter, MakeCountedConstantIterator(InValue, Count), DefaultSentinel); return Insert(Iter, Ranges::Repeat(InValue, Count));
} }
/** Inserts elements from range ['First', 'Last') before 'Iter'. */ /** Inserts elements from range ['First', 'Last') before 'Iter'. */
template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<ElementType, TIteratorReferenceType<I>>) template <CInputIterator I, CSentinelFor<I> S> requires (CConstructibleFrom<FElementType, TIteratorReference<I>>)
Iterator Insert(ConstIterator Iter, I First, S Last) FIterator Insert(FConstIterator Iter, I First, S Last)
{ {
if (First == Last) return Iterator(Iter.Pointer); if (First == Last) return FIterator(Iter.Pointer);
FNode* InsertNode = Iter.Pointer->PrevNode; FNode* InsertNode = Iter.Pointer->PrevNode;
@ -279,15 +286,19 @@ public:
InsertNode->NextNode = Iter.Pointer; InsertNode->NextNode = Iter.Pointer;
Iter.Pointer->PrevNode = InsertNode; Iter.Pointer->PrevNode = InsertNode;
return Iterator(FirstNode); return FIterator(FirstNode);
} }
/** 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, Ranges::Begin(Range), Ranges::End(Range)); }
/** Inserts elements from initializer list before 'Iter' in the container. */ /** Inserts elements from initializer list before 'Iter' in the container. */
FORCEINLINE Iterator Insert(ConstIterator Iter, initializer_list<ElementType> IL) requires (CCopyConstructible<ElementType>) { return Insert(Iter, Iteration::Begin(IL), Iteration::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'. */ /** Inserts a new element into the container directly before 'Iter'. */
template <typename... Ts> requires (CConstructibleFrom<ElementType, Ts...>) template <typename... Ts> requires (CConstructibleFrom<FElementType, Ts...>)
Iterator Emplace(ConstIterator Iter, Ts&&... Args) FIterator Emplace(FConstIterator Iter, Ts&&... Args)
{ {
FNode* Node = new (Impl->Allocate(1)) FNode(InPlace, Forward<Ts>(Args)...); FNode* Node = new (Impl->Allocate(1)) FNode(InPlace, Forward<Ts>(Args)...);
@ -299,11 +310,11 @@ public:
Node->PrevNode->NextNode = Node; Node->PrevNode->NextNode = Node;
Node->NextNode->PrevNode = Node; Node->NextNode->PrevNode = Node;
return Iterator(Node); return FIterator(Node);
} }
/** Removes the element at 'Iter' in the container. */ /** Removes the element at 'Iter' in the container. */
Iterator Erase(ConstIterator Iter) FIterator Erase(FConstIterator Iter)
{ {
FNode* NodeToErase = Iter.Pointer; FNode* NodeToErase = Iter.Pointer;
@ -319,11 +330,11 @@ public:
--Impl.ListNum; --Impl.ListNum;
return Iterator(NextNode); return FIterator(NextNode);
} }
/** Removes the elements in the range ['First', 'Last') in the container. */ /** Removes the elements in the range ['First', 'Last') in the container. */
Iterator Erase(ConstIterator First, ConstIterator Last) FIterator Erase(FConstIterator First, FConstIterator Last)
{ {
FNode* FirstToErase = First.Pointer; FNode* FirstToErase = First.Pointer;
FNode* LastToErase = Last.Pointer; FNode* LastToErase = Last.Pointer;
@ -343,45 +354,45 @@ public:
FirstToErase = NextNode; FirstToErase = NextNode;
} }
return Iterator(LastToErase); return FIterator(LastToErase);
} }
/** Appends the given element value to the end of the container. */ /** Appends the given element value to the end of the container. */
FORCEINLINE void PushBack(const ElementType& InValue) requires (CCopyConstructible<ElementType>) { EmplaceBack(InValue); } FORCEINLINE void PushBack(const FElementType& InValue) requires (CCopyConstructible<FElementType>) { EmplaceBack(InValue); }
/** Appends the given element value to the end of the container. */ /** Appends the given element value to the end of the container. */
FORCEINLINE void PushBack(ElementType&& InValue) requires (CMoveConstructible<ElementType>) { EmplaceBack(MoveTemp(InValue)); } FORCEINLINE void PushBack(FElementType&& InValue) requires (CMoveConstructible<FElementType>) { EmplaceBack(MoveTemp(InValue)); }
/** Appends a new element to the end of the container. */ /** Appends a new element to the end of the container. */
template <typename... Ts> requires (CConstructibleFrom<ElementType, Ts...>) template <typename... Ts> requires (CConstructibleFrom<FElementType, Ts...>)
FORCEINLINE Reference EmplaceBack(Ts&&... Args) { return *Emplace(End(), Forward<Ts>(Args)...); } FORCEINLINE FReference EmplaceBack(Ts&&... Args) { return *Emplace(End(), Forward<Ts>(Args)...); }
/** Removes the last element of the container. The list cannot be empty. */ /** Removes the last element of the container. The list cannot be empty. */
FORCEINLINE void PopBack() { Erase(--End()); } FORCEINLINE void PopBack() { Erase(--End()); }
/** Prepends the given element value to the beginning of the container. */ /** Prepends the given element value to the beginning of the container. */
FORCEINLINE void PushFront(const ElementType& InValue) requires (CCopyConstructible<ElementType>) { EmplaceFront(InValue); } FORCEINLINE void PushFront(const FElementType& InValue) requires (CCopyConstructible<FElementType>) { EmplaceFront(InValue); }
/** Prepends the given element value to the beginning of the container. */ /** Prepends the given element value to the beginning of the container. */
FORCEINLINE void PushFront(ElementType&& InValue) requires (CMoveConstructible<ElementType>) { EmplaceFront(MoveTemp(InValue)); } FORCEINLINE void PushFront(FElementType&& InValue) requires (CMoveConstructible<FElementType>) { EmplaceFront(MoveTemp(InValue)); }
/** Prepends a new element to the beginning of the container. */ /** Prepends a new element to the beginning of the container. */
template <typename... Ts> requires (CConstructibleFrom<ElementType, Ts...>) template <typename... Ts> requires (CConstructibleFrom<FElementType, Ts...>)
FORCEINLINE Reference EmplaceFront(Ts&&... Args) { return *Emplace(Begin(), Forward<Ts>(Args)...); } FORCEINLINE FReference EmplaceFront(Ts&&... Args) { return *Emplace(Begin(), Forward<Ts>(Args)...); }
/** Removes the first element of the container. The list cannot be empty. */ /** Removes the first element of the container. The list cannot be empty. */
FORCEINLINE void PopFront() { Erase(Begin()); } FORCEINLINE void PopFront() { Erase(Begin()); }
/** Resizes the container to contain 'Count' elements. Additional default elements are appended. */ /** Resizes the container to contain 'Count' elements. Additional default elements are appended. */
void SetNum(size_t Count) requires (CDefaultConstructible<ElementType>) void SetNum(size_t Count) requires (CDefaultConstructible<FElementType>)
{ {
if (Count == Impl.ListNum) return; if (Count == Impl.ListNum) return;
if (Count < Impl.ListNum) if (Count < Impl.ListNum)
{ {
Iterator First = End(); FIterator First = End();
Iteration::Advance(First, Count - Impl.ListNum); for (size_t Index = 0; Index != Impl.ListNum - Count; ++Index) --First;
Erase(First, End()); Erase(First, End());
@ -409,15 +420,15 @@ public:
} }
/** Resizes the container to contain 'Count' elements. Additional copies of 'InValue' are appended. */ /** Resizes the container to contain 'Count' elements. Additional copies of 'InValue' are appended. */
void SetNum(size_t Count, const ElementType& InValue) requires (CCopyConstructible<ElementType>) void SetNum(size_t Count, const FElementType& InValue) requires (CCopyConstructible<FElementType>)
{ {
if (Count == Impl.ListNum) return; if (Count == Impl.ListNum) return;
if (Count < Impl.ListNum) if (Count < Impl.ListNum)
{ {
Iterator First = End(); FIterator First = End();
Iteration::Advance(First, Count - Impl.ListNum); for (size_t Index = 0; Index != Impl.ListNum - Count; ++Index) --First;
Erase(First, End()); Erase(First, End());
@ -445,16 +456,16 @@ public:
} }
/** @return The iterator to the first or end element. */ /** @return The iterator to the first or end element. */
NODISCARD FORCEINLINE Iterator Begin() { return Iterator(Impl.HeadNode->NextNode); } NODISCARD FORCEINLINE FIterator Begin() { return FIterator(Impl.HeadNode->NextNode); }
NODISCARD FORCEINLINE ConstIterator Begin() const { return ConstIterator(Impl.HeadNode->NextNode); } NODISCARD FORCEINLINE FConstIterator Begin() const { return FConstIterator(Impl.HeadNode->NextNode); }
NODISCARD FORCEINLINE Iterator End() { return Iterator(Impl.HeadNode); } NODISCARD FORCEINLINE FIterator End() { return FIterator(Impl.HeadNode); }
NODISCARD FORCEINLINE ConstIterator End() const { return ConstIterator(Impl.HeadNode); } NODISCARD FORCEINLINE FConstIterator End() const { return FConstIterator(Impl.HeadNode); }
/** @return The reverse iterator to the first or end element. */ /** @return The reverse iterator to the first or end element. */
NODISCARD FORCEINLINE ReverseIterator RBegin() { return ReverseIterator(End()); } NODISCARD FORCEINLINE FReverseIterator RBegin() { return FReverseIterator(End()); }
NODISCARD FORCEINLINE ConstReverseIterator RBegin() const { return ConstReverseIterator(End()); } NODISCARD FORCEINLINE FConstReverseIterator RBegin() const { return FConstReverseIterator(End()); }
NODISCARD FORCEINLINE ReverseIterator REnd() { return ReverseIterator(Begin()); } NODISCARD FORCEINLINE FReverseIterator REnd() { return FReverseIterator(Begin()); }
NODISCARD FORCEINLINE ConstReverseIterator REnd() const { return ConstReverseIterator(Begin()); } NODISCARD FORCEINLINE FConstReverseIterator REnd() const { return FConstReverseIterator(Begin()); }
/** @return The number of elements in the container. */ /** @return The number of elements in the container. */
NODISCARD FORCEINLINE size_t Num() const { return Impl.ListNum; } NODISCARD FORCEINLINE size_t Num() const { return Impl.ListNum; }
@ -463,7 +474,7 @@ public:
NODISCARD FORCEINLINE bool IsEmpty() const { return Num() == 0; } NODISCARD FORCEINLINE bool IsEmpty() const { return Num() == 0; }
/** @return true if the iterator is valid, false otherwise. */ /** @return true if the iterator is valid, false otherwise. */
NODISCARD FORCEINLINE bool IsValidIterator(ConstIterator Iter) const NODISCARD FORCEINLINE bool IsValidIterator(FConstIterator Iter) const
{ {
FNode* Current = Impl.HeadNode; FNode* Current = Impl.HeadNode;
@ -481,10 +492,10 @@ public:
} }
/** @return The reference to the first or last element. */ /** @return The reference to the first or last element. */
NODISCARD FORCEINLINE ElementType& Front() { return *Begin(); } NODISCARD FORCEINLINE FElementType& Front() { return *Begin(); }
NODISCARD FORCEINLINE const ElementType& Front() const { return *Begin(); } NODISCARD FORCEINLINE const FElementType& Front() const { return *Begin(); }
NODISCARD FORCEINLINE ElementType& Back() { return *(End() - 1); } NODISCARD FORCEINLINE FElementType& Back() { return *(End() - 1); }
NODISCARD FORCEINLINE const ElementType& Back() const { return *(End() - 1); } NODISCARD FORCEINLINE const FElementType& Back() const { return *(End() - 1); }
/** Erases all elements from the container. After this call, Num() returns zero. */ /** Erases all elements from the container. After this call, Num() returns zero. */
void Reset() void Reset()
@ -508,11 +519,11 @@ public:
} }
/** Overloads the GetTypeHash algorithm for TList. */ /** Overloads the GetTypeHash algorithm for TList. */
NODISCARD friend FORCEINLINE size_t GetTypeHash(const TList& A) requires (CHashable<ElementType>) NODISCARD friend FORCEINLINE size_t GetTypeHash(const TList& A) requires (CHashable<FElementType>)
{ {
size_t Result = 0; size_t Result = 0;
for (const ElementType& Element : A) for (const FElementType& Element : A)
{ {
Result = HashCombine(Result, GetTypeHash(Element)); Result = HashCombine(Result, GetTypeHash(Element));
} }
@ -535,7 +546,7 @@ private:
{ {
FNode* PrevNode; FNode* PrevNode;
FNode* NextNode; FNode* NextNode;
ElementType Value; FElementType Value;
FORCEINLINE FNode() = default; FORCEINLINE FNode() = default;
@ -543,21 +554,21 @@ private:
FORCEINLINE FNode(FInPlace, Ts&&... Args) : Value(Forward<Ts>(Args)...) { } FORCEINLINE FNode(FInPlace, Ts&&... Args) : Value(Forward<Ts>(Args)...) { }
}; };
static_assert(CMultipleAllocator<AllocatorType, FNode>); static_assert(CMultipleAllocator<FAllocatorType, FNode>);
ALLOCATOR_WRAPPER_BEGIN(AllocatorType, FNode, Impl) ALLOCATOR_WRAPPER_BEGIN(FAllocatorType, FNode, Impl)
{ {
FNode* HeadNode; FNode* HeadNode;
size_t ListNum; size_t ListNum;
} }
ALLOCATOR_WRAPPER_END(AllocatorType, FNode, Impl) ALLOCATOR_WRAPPER_END(FAllocatorType, FNode, Impl)
template <bool bConst, typename U> template <bool bConst, typename U>
class TIteratorImpl final class TIteratorImpl final
{ {
public: public:
using ElementType = TRemoveCV<T>; using FElementType = TRemoveCV<T>;
FORCEINLINE TIteratorImpl() = default; FORCEINLINE TIteratorImpl() = default;
@ -598,7 +609,10 @@ private:
}; };
template <typename I, typename S> template <typename I, typename S>
TList(I, S) -> TList<TIteratorElementType<I>>; TList(I, S) -> TList<TIteratorElement<I>>;
template <typename R>
TList(R) -> TList<TRangeElement<R>>;
template <typename T> template <typename T>
TList(initializer_list<T>) -> TList<T>; TList(initializer_list<T>) -> TList<T>;

View File

@ -1,13 +1,14 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Templates/Meta.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.h"
#include "Templates/Meta.h"
#include "Templates/TypeHash.h"
#include "Iterators/Utility.h"
#include "Iterators/BasicIterator.h"
#include "Iterators/ReverseIterator.h"
#include "Miscellaneous/Compare.h" #include "Miscellaneous/Compare.h"
#include "Miscellaneous/Iterator.h"
#include "Miscellaneous/Container.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
@ -15,7 +16,7 @@ NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_MODULE_BEGIN(Utility)
/** TStaticArray is a container that encapsulates fixed size arrays. */ /** TStaticArray is a container that encapsulates fixed size arrays. */
template <CObject T, size_t N> template <CObject T, size_t N> requires (!CConst<T> && !CVolatile<T>)
struct TStaticArray struct TStaticArray
{ {
private: private:
@ -25,22 +26,22 @@ private:
public: public:
using ElementType = T; using FElementType = T;
using Reference = T&; using FReference = T&;
using ConstReference = const T&; using FConstReference = const T&;
using Iterator = TIteratorImpl<false>; using FIterator = TIteratorImpl<false>;
using ConstIterator = TIteratorImpl<true >; using FConstIterator = TIteratorImpl<true >;
using ReverseIterator = TReverseIterator< Iterator>; using FReverseIterator = TReverseIterator< FIterator>;
using ConstReverseIterator = TReverseIterator<ConstIterator>; using FConstReverseIterator = TReverseIterator<FConstIterator>;
static_assert(CContiguousIterator< Iterator>); static_assert(CContiguousIterator< FIterator>);
static_assert(CContiguousIterator<ConstIterator>); static_assert(CContiguousIterator<FConstIterator>);
/** Compares the contents of two arrays. */ /** Compares the contents of two arrays. */
NODISCARD friend constexpr bool operator==(const TStaticArray& LHS, const TStaticArray& RHS) requires (CWeaklyEqualityComparable<ElementType>) NODISCARD friend constexpr bool operator==(const TStaticArray& LHS, const TStaticArray& RHS) requires (CWeaklyEqualityComparable<FElementType>)
{ {
if (LHS.Num() != RHS.Num()) return false; if (LHS.Num() != RHS.Num()) return false;
@ -53,7 +54,7 @@ public:
} }
/** Compares the contents of 'LHS' and 'RHS' lexicographically. */ /** Compares the contents of 'LHS' and 'RHS' lexicographically. */
NODISCARD friend constexpr auto operator<=>(const TStaticArray& LHS, const TStaticArray& RHS) requires (CSynthThreeWayComparable<ElementType>) NODISCARD friend constexpr auto operator<=>(const TStaticArray& LHS, const TStaticArray& RHS) requires (CSynthThreeWayComparable<FElementType>)
{ {
const size_t NumToCompare = LHS.Num() < RHS.Num() ? LHS.Num() : RHS.Num(); const size_t NumToCompare = LHS.Num() < RHS.Num() ? LHS.Num() : RHS.Num();
@ -66,20 +67,20 @@ public:
} }
/** @return The pointer to the underlying element storage. */ /** @return The pointer to the underlying element storage. */
NODISCARD FORCEINLINE constexpr ElementType* GetData() { return _; } NODISCARD FORCEINLINE constexpr FElementType* GetData() { return _; }
NODISCARD FORCEINLINE constexpr const ElementType* GetData() const { return _; } NODISCARD FORCEINLINE constexpr const FElementType* GetData() const { return _; }
/** @return The iterator to the first or end element. */ /** @return The iterator to the first or end element. */
NODISCARD FORCEINLINE constexpr Iterator Begin() { return Iterator(this, _); } NODISCARD FORCEINLINE constexpr FIterator Begin() { return FIterator(this, _); }
NODISCARD FORCEINLINE constexpr ConstIterator Begin() const { return ConstIterator(this, _); } NODISCARD FORCEINLINE constexpr FConstIterator Begin() const { return FConstIterator(this, _); }
NODISCARD FORCEINLINE constexpr Iterator End() { return Iterator(this, _ + Num()); } NODISCARD FORCEINLINE constexpr FIterator End() { return FIterator(this, _ + Num()); }
NODISCARD FORCEINLINE constexpr ConstIterator End() const { return ConstIterator(this, _ + Num()); } NODISCARD FORCEINLINE constexpr FConstIterator End() const { return FConstIterator(this, _ + Num()); }
/** @return The reverse iterator to the first or end element. */ /** @return The reverse iterator to the first or end element. */
NODISCARD FORCEINLINE constexpr ReverseIterator RBegin() { return ReverseIterator(End()); } NODISCARD FORCEINLINE constexpr FReverseIterator RBegin() { return FReverseIterator(End()); }
NODISCARD FORCEINLINE constexpr ConstReverseIterator RBegin() const { return ConstReverseIterator(End()); } NODISCARD FORCEINLINE constexpr FConstReverseIterator RBegin() const { return FConstReverseIterator(End()); }
NODISCARD FORCEINLINE constexpr ReverseIterator REnd() { return ReverseIterator(Begin()); } NODISCARD FORCEINLINE constexpr FReverseIterator REnd() { return FReverseIterator(Begin()); }
NODISCARD FORCEINLINE constexpr ConstReverseIterator REnd() const { return ConstReverseIterator(Begin()); } NODISCARD FORCEINLINE constexpr FConstReverseIterator REnd() const { return FConstReverseIterator(Begin()); }
/** @return The number of elements in the container. */ /** @return The number of elements in the container. */
NODISCARD FORCEINLINE constexpr size_t Num() const { return N; } NODISCARD FORCEINLINE constexpr size_t Num() const { return N; }
@ -88,24 +89,24 @@ public:
NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return Num() == 0; } NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return Num() == 0; }
/** @return true if the iterator is valid, false otherwise. */ /** @return true if the iterator is valid, false otherwise. */
NODISCARD FORCEINLINE constexpr bool IsValidIterator(ConstIterator Iter) const { return Begin() <= Iter && Iter <= End(); } NODISCARD FORCEINLINE constexpr bool IsValidIterator(FConstIterator Iter) const { return Begin() <= Iter && Iter <= End(); }
/** @return The reference to the requested element. */ /** @return The reference to the requested element. */
NODISCARD FORCEINLINE constexpr ElementType& operator[](size_t Index) { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return _[Index]; } NODISCARD FORCEINLINE constexpr FElementType& operator[](size_t Index) { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return _[Index]; }
NODISCARD FORCEINLINE constexpr const ElementType& operator[](size_t Index) const { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return _[Index]; } NODISCARD FORCEINLINE constexpr const FElementType& operator[](size_t Index) const { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return _[Index]; }
/** @return The reference to the first or last element. */ /** @return The reference to the first or last element. */
NODISCARD FORCEINLINE constexpr ElementType& Front() { return *Begin(); } NODISCARD FORCEINLINE constexpr FElementType& Front() { return *Begin(); }
NODISCARD FORCEINLINE constexpr const ElementType& Front() const { return *Begin(); } NODISCARD FORCEINLINE constexpr const FElementType& Front() const { return *Begin(); }
NODISCARD FORCEINLINE constexpr ElementType& Back() { return *(End() - 1); } NODISCARD FORCEINLINE constexpr FElementType& Back() { return *(End() - 1); }
NODISCARD FORCEINLINE constexpr const ElementType& Back() const { return *(End() - 1); } NODISCARD FORCEINLINE constexpr const FElementType& Back() const { return *(End() - 1); }
/** Overloads the GetTypeHash algorithm for TStaticArray. */ /** Overloads the GetTypeHash algorithm for TStaticArray. */
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TStaticArray& A) requires (CHashable<ElementType>) NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TStaticArray& A) requires (CHashable<FElementType>)
{ {
size_t Result = 0; size_t Result = 0;
for (ConstIterator Iter = A.Begin(); Iter != A.End(); ++Iter) for (FConstIterator Iter = A.Begin(); Iter != A.End(); ++Iter)
{ {
Result = HashCombine(Result, GetTypeHash(*Iter)); Result = HashCombine(Result, GetTypeHash(*Iter));
} }
@ -114,7 +115,7 @@ public:
} }
/** Overloads the Swap algorithm for TStaticArray. */ /** Overloads the Swap algorithm for TStaticArray. */
friend FORCEINLINE constexpr void Swap(TStaticArray& A, TStaticArray& B) requires (CSwappable<ElementType>) { Swap(A._, B._); } friend FORCEINLINE constexpr void Swap(TStaticArray& A, TStaticArray& B) requires (CSwappable<FElementType>) { Swap(A._, B._); }
ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT ENABLE_RANGE_BASED_FOR_LOOP_SUPPORT
@ -127,7 +128,7 @@ private:
{ {
public: public:
using ElementType = TRemoveCV<T>; using FElementType = TRemoveCV<T>;
FORCEINLINE constexpr TIteratorImpl() = default; FORCEINLINE constexpr TIteratorImpl() = default;
@ -224,6 +225,8 @@ NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END
// ReSharper disable CppInconsistentNaming
NAMESPACE_STD_BEGIN NAMESPACE_STD_BEGIN
// Support structure binding, should not be directly used. // Support structure binding, should not be directly used.
@ -245,3 +248,5 @@ template <size_t Index, typename T, size_t N> FORCEINLINE constexpr decltype(aut
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END
// ReSharper restore CppInconsistentNaming

View File

@ -1,14 +1,14 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "Templates/TypeHash.h" #include "Templates/TypeHash.h"
#include "Templates/Noncopyable.h" #include "Templates/Noncopyable.h"
#include "TypeTraits/TypeTraits.h" #include "Iterators/Utility.h"
#include "Iterators/BasicIterator.h"
#include "Iterators/ReverseIterator.h"
#include "Miscellaneous/Compare.h" #include "Miscellaneous/Compare.h"
#include "Memory/MemoryOperator.h"
#include "Miscellaneous/Iterator.h"
#include "Miscellaneous/Container.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
@ -25,9 +25,7 @@ using TDefaultBitsetBlockType =
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
#if 1 template <size_t N, CUnsignedIntegral InBlockType = NAMESPACE_PRIVATE::TDefaultBitsetBlockType<N>> requires (!CConst<InBlockType> && !CVolatile<InBlockType> && !CSameAs<InBlockType, bool>)
template <size_t N, CUnsignedIntegral InBlockType = NAMESPACE_PRIVATE::TDefaultBitsetBlockType<N>> requires (!CSameAs<InBlockType, bool>)
class TStaticBitset class TStaticBitset
{ {
private: private:
@ -37,22 +35,22 @@ private:
public: public:
using BlockType = InBlockType; using FBlockType = InBlockType;
using ElementType = bool; using FElementType = bool;
class Reference; class FReference;
using ConstReference = bool; using FConstReference = bool;
using Iterator = TIteratorImpl<false>; using FIterator = TIteratorImpl<false>;
using ConstIterator = TIteratorImpl<true >; using FConstIterator = TIteratorImpl<true >;
using ReverseIterator = TReverseIterator< Iterator>; using FReverseIterator = TReverseIterator< FIterator>;
using ConstReverseIterator = TReverseIterator<ConstIterator>; using FConstReverseIterator = TReverseIterator<FConstIterator>;
static_assert(CRandomAccessIterator< Iterator>); static_assert(CRandomAccessIterator< FIterator>);
static_assert(CRandomAccessIterator<ConstIterator>); static_assert(CRandomAccessIterator<FConstIterator>);
static constexpr size_t BlockWidth = sizeof(BlockType) * 8; static constexpr size_t BlockWidth = sizeof(FBlockType) * 8;
/** Default constructor. Constructs an empty bitset. */ /** Default constructor. Constructs an empty bitset. */
FORCEINLINE constexpr TStaticBitset() = default; FORCEINLINE constexpr TStaticBitset() = default;
@ -60,38 +58,38 @@ public:
/** Constructs a bitset from an integer. */ /** Constructs a bitset from an integer. */
constexpr TStaticBitset(uint64 InValue) constexpr TStaticBitset(uint64 InValue)
{ {
static_assert(sizeof(BlockType) <= sizeof(uint64), "The block width of TStaticBitset is unexpected"); static_assert(sizeof(FBlockType) <= sizeof(uint64), "The block width of TStaticBitset is unexpected");
if constexpr (sizeof(BlockType) == sizeof(uint8)) if constexpr (sizeof(FBlockType) == sizeof(uint8))
{ {
if constexpr (N > 0) Impl[0] = static_cast<BlockType>(InValue >> 0); if constexpr (N > 0) Impl[0] = static_cast<FBlockType>(InValue >> 0);
if constexpr (N > 8) Impl[1] = static_cast<BlockType>(InValue >> 8); if constexpr (N > 8) Impl[1] = static_cast<FBlockType>(InValue >> 8);
if constexpr (N > 16) Impl[2] = static_cast<BlockType>(InValue >> 16); if constexpr (N > 16) Impl[2] = static_cast<FBlockType>(InValue >> 16);
if constexpr (N > 24) Impl[3] = static_cast<BlockType>(InValue >> 24); if constexpr (N > 24) Impl[3] = static_cast<FBlockType>(InValue >> 24);
if constexpr (N > 32) Impl[4] = static_cast<BlockType>(InValue >> 32); if constexpr (N > 32) Impl[4] = static_cast<FBlockType>(InValue >> 32);
if constexpr (N > 40) Impl[5] = static_cast<BlockType>(InValue >> 40); if constexpr (N > 40) Impl[5] = static_cast<FBlockType>(InValue >> 40);
if constexpr (N > 48) Impl[6] = static_cast<BlockType>(InValue >> 48); if constexpr (N > 48) Impl[6] = static_cast<FBlockType>(InValue >> 48);
if constexpr (N > 56) Impl[7] = static_cast<BlockType>(InValue >> 56); if constexpr (N > 56) Impl[7] = static_cast<FBlockType>(InValue >> 56);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint16)) else if constexpr (sizeof(FBlockType) == sizeof(uint16))
{ {
if constexpr (N > 0) Impl[0] = static_cast<BlockType>(InValue >> 0); if constexpr (N > 0) Impl[0] = static_cast<FBlockType>(InValue >> 0);
if constexpr (N > 16) Impl[1] = static_cast<BlockType>(InValue >> 16); if constexpr (N > 16) Impl[1] = static_cast<FBlockType>(InValue >> 16);
if constexpr (N > 32) Impl[2] = static_cast<BlockType>(InValue >> 32); if constexpr (N > 32) Impl[2] = static_cast<FBlockType>(InValue >> 32);
if constexpr (N > 48) Impl[3] = static_cast<BlockType>(InValue >> 48); if constexpr (N > 48) Impl[3] = static_cast<FBlockType>(InValue >> 48);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint32)) else if constexpr (sizeof(FBlockType) == sizeof(uint32))
{ {
if constexpr (N > 0) Impl[0] = static_cast<BlockType>(InValue >> 0); if constexpr (N > 0) Impl[0] = static_cast<FBlockType>(InValue >> 0);
if constexpr (N > 32) Impl[1] = static_cast<BlockType>(InValue >> 32); if constexpr (N > 32) Impl[1] = static_cast<FBlockType>(InValue >> 32);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint64)) else if constexpr (sizeof(FBlockType) == sizeof(uint64))
{ {
if constexpr (N > 0) Impl[0] = static_cast<BlockType>(InValue >> 0); if constexpr (N > 0) Impl[0] = static_cast<FBlockType>(InValue >> 0);
} }
else check_no_entry(); else check_no_entry();
constexpr size_t BlockInteger = sizeof(uint64) / sizeof(BlockType); constexpr size_t BlockInteger = sizeof(uint64) / sizeof(FBlockType);
if constexpr ((N + BlockWidth - 1) / BlockWidth <= BlockInteger) return; if constexpr ((N + BlockWidth - 1) / BlockWidth <= BlockInteger) return;
@ -126,7 +124,7 @@ public:
if (LHS.Impl[Index] != RHS.Impl[Index]) return false; if (LHS.Impl[Index] != RHS.Impl[Index]) return false;
} }
const BlockType LastBlockBitmask = LHS.Num() % BlockWidth != 0 ? (1ull << LHS.Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = LHS.Num() % BlockWidth != 0 ? (1ull << LHS.Num() % BlockWidth) - 1 : -1;
return (LHS.Impl[LHS.NumBlocks() - 1] & LastBlockBitmask) == (RHS.Impl[LHS.NumBlocks() - 1] & LastBlockBitmask); return (LHS.Impl[LHS.NumBlocks() - 1] & LastBlockBitmask) == (RHS.Impl[LHS.NumBlocks() - 1] & LastBlockBitmask);
} }
@ -269,7 +267,7 @@ public:
if (Impl[Index] != -1) return false; if (Impl[Index] != -1) return false;
} }
const BlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1;
return (Impl[NumBlocks() - 1] | ~LastBlockBitmask) == -1; return (Impl[NumBlocks() - 1] | ~LastBlockBitmask) == -1;
} }
@ -284,7 +282,7 @@ public:
if (Impl[Index] != 0) return true; if (Impl[Index] != 0) return true;
} }
const BlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1;
return (Impl[NumBlocks() - 1] & LastBlockBitmask) != 0; return (Impl[NumBlocks() - 1] & LastBlockBitmask) != 0;
} }
@ -299,24 +297,24 @@ public:
size_t Result = 0; size_t Result = 0;
constexpr auto BlockCount = [](BlockType Block) constexpr constexpr auto BlockCount = [](FBlockType Block) constexpr
{ {
static_assert(sizeof(BlockType) <= sizeof(uint64), "The block width of TStaticBitset is unexpected"); static_assert(sizeof(FBlockType) <= sizeof(uint64), "The block width of TStaticBitset is unexpected");
if constexpr (sizeof(BlockType) == sizeof(uint8)) if constexpr (sizeof(FBlockType) == sizeof(uint8))
{ {
Block = (Block & 0x55ull) + ((Block >> 1) & 0x55ull); Block = (Block & 0x55ull) + ((Block >> 1) & 0x55ull);
Block = (Block & 0x33ull) + ((Block >> 2) & 0x33ull); Block = (Block & 0x33ull) + ((Block >> 2) & 0x33ull);
Block = (Block & 0x0Full) + ((Block >> 4) & 0x0Full); Block = (Block & 0x0Full) + ((Block >> 4) & 0x0Full);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint16)) else if constexpr (sizeof(FBlockType) == sizeof(uint16))
{ {
Block = (Block & 0x5555ull) + ((Block >> 1) & 0x5555ull); Block = (Block & 0x5555ull) + ((Block >> 1) & 0x5555ull);
Block = (Block & 0x3333ull) + ((Block >> 2) & 0x3333ull); Block = (Block & 0x3333ull) + ((Block >> 2) & 0x3333ull);
Block = (Block & 0x0F0Full) + ((Block >> 4) & 0x0F0Full); Block = (Block & 0x0F0Full) + ((Block >> 4) & 0x0F0Full);
Block = (Block & 0x00FFull) + ((Block >> 8) & 0x00FFull); Block = (Block & 0x00FFull) + ((Block >> 8) & 0x00FFull);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint32)) else if constexpr (sizeof(FBlockType) == sizeof(uint32))
{ {
Block = (Block & 0x55555555ull) + ((Block >> 1) & 0x55555555ull); Block = (Block & 0x55555555ull) + ((Block >> 1) & 0x55555555ull);
Block = (Block & 0x33333333ull) + ((Block >> 2) & 0x33333333ull); Block = (Block & 0x33333333ull) + ((Block >> 2) & 0x33333333ull);
@ -324,7 +322,7 @@ public:
Block = (Block & 0x00FF00FFull) + ((Block >> 8) & 0x00FF00FFull); Block = (Block & 0x00FF00FFull) + ((Block >> 8) & 0x00FF00FFull);
Block = (Block & 0x0000FFFFull) + ((Block >> 16) & 0x0000FFFFull); Block = (Block & 0x0000FFFFull) + ((Block >> 16) & 0x0000FFFFull);
} }
else if constexpr (sizeof(BlockType) == sizeof(uint64)) else if constexpr (sizeof(FBlockType) == sizeof(uint64))
{ {
Block = (Block & 0x5555555555555555ull) + ((Block >> 1) & 0x5555555555555555ull); Block = (Block & 0x5555555555555555ull) + ((Block >> 1) & 0x5555555555555555ull);
Block = (Block & 0x3333333333333333ull) + ((Block >> 2) & 0x3333333333333333ull); Block = (Block & 0x3333333333333333ull) + ((Block >> 2) & 0x3333333333333333ull);
@ -343,7 +341,7 @@ public:
Result += BlockCount(Impl[Index]); Result += BlockCount(Impl[Index]);
} }
const BlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1;
Result += BlockCount(Impl[NumBlocks() - 1] & LastBlockBitmask); Result += BlockCount(Impl[NumBlocks() - 1] & LastBlockBitmask);
@ -355,7 +353,7 @@ public:
{ {
for (size_t Index = 0; Index != NumBlocks(); ++Index) for (size_t Index = 0; Index != NumBlocks(); ++Index)
{ {
Impl[Index] = static_cast<BlockType>(InValue ? -1 : 0); Impl[Index] = static_cast<FBlockType>(InValue ? -1 : 0);
} }
return *this; return *this;
@ -387,20 +385,20 @@ public:
{ {
for (size_t Index = 64 / BlockWidth; Index < NumBlocks() - 1; ++Index) for (size_t Index = 64 / BlockWidth; Index < NumBlocks() - 1; ++Index)
{ {
checkf(Impl.Pointer[Index] != 0, TEXT("The bitset can not be represented in uint64. Please check Num().")); checkf(Impl[Index] != 0, TEXT("The bitset can not be represented in uint64. Please check Num()."));
} }
const BlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = Num() % BlockWidth != 0 ? (1ull << Num() % BlockWidth) - 1 : -1;
const BlockType LastBlock = Impl.Pointer[NumBlocks() - 1] & LastBlockBitmask; const FBlockType LastBlock = Impl[NumBlocks() - 1] & LastBlockBitmask;
checkf(LastBlock != 0, TEXT("The bitset can not be represented in uint64. Please check Num().")); checkf(LastBlock != 0, TEXT("The bitset can not be represented in uint64. Please check Num()."));
} }
uint64 Result = 0; uint64 Result = 0;
static_assert(sizeof(BlockType) <= sizeof(uint64), "The block width of TStaticBitset is unexpected"); static_assert(sizeof(FBlockType) <= sizeof(uint64), "The block width of TStaticBitset is unexpected");
if constexpr (sizeof(BlockType) == sizeof(uint8)) if constexpr (sizeof(FBlockType) == sizeof(uint8))
{ {
if constexpr (N > 0) Result |= static_cast<uint64>(Impl[0]) << 0; if constexpr (N > 0) Result |= static_cast<uint64>(Impl[0]) << 0;
if constexpr (N > 8) Result |= static_cast<uint64>(Impl[1]) << 8; if constexpr (N > 8) Result |= static_cast<uint64>(Impl[1]) << 8;
@ -411,19 +409,19 @@ public:
if constexpr (N > 48) Result |= static_cast<uint64>(Impl[6]) << 48; if constexpr (N > 48) Result |= static_cast<uint64>(Impl[6]) << 48;
if constexpr (N > 56) Result |= static_cast<uint64>(Impl[7]) << 56; if constexpr (N > 56) Result |= static_cast<uint64>(Impl[7]) << 56;
} }
else if constexpr (sizeof(BlockType) == sizeof(uint16)) else if constexpr (sizeof(FBlockType) == sizeof(uint16))
{ {
if constexpr (N > 0) Result |= static_cast<uint64>(Impl[0]) << 0; if constexpr (N > 0) Result |= static_cast<uint64>(Impl[0]) << 0;
if constexpr (N > 16) Result |= static_cast<uint64>(Impl[1]) << 16; if constexpr (N > 16) Result |= static_cast<uint64>(Impl[1]) << 16;
if constexpr (N > 32) Result |= static_cast<uint64>(Impl[2]) << 32; if constexpr (N > 32) Result |= static_cast<uint64>(Impl[2]) << 32;
if constexpr (N > 48) Result |= static_cast<uint64>(Impl[3]) << 48; if constexpr (N > 48) Result |= static_cast<uint64>(Impl[3]) << 48;
} }
else if constexpr (sizeof(BlockType) == sizeof(uint32)) else if constexpr (sizeof(FBlockType) == sizeof(uint32))
{ {
if constexpr (N > 0) Result |= static_cast<uint64>(Impl[0]) << 0; if constexpr (N > 0) Result |= static_cast<uint64>(Impl[0]) << 0;
if constexpr (N > 32) Result |= static_cast<uint64>(Impl[1]) << 32; if constexpr (N > 32) Result |= static_cast<uint64>(Impl[1]) << 32;
} }
else if constexpr (sizeof(BlockType) == sizeof(uint64)) else if constexpr (sizeof(FBlockType) == sizeof(uint64))
{ {
if constexpr (N > 0) Result |= static_cast<uint64>(Impl[0]) << 0; if constexpr (N > 0) Result |= static_cast<uint64>(Impl[0]) << 0;
} }
@ -435,20 +433,20 @@ public:
} }
/** @return The pointer to the underlying element storage. */ /** @return The pointer to the underlying element storage. */
NODISCARD FORCEINLINE constexpr BlockType* GetData() { return Impl; } NODISCARD FORCEINLINE constexpr FBlockType* GetData() { return Impl; }
NODISCARD FORCEINLINE constexpr const BlockType* GetData() const { return Impl; } NODISCARD FORCEINLINE constexpr const FBlockType* GetData() const { return Impl; }
/** @return The iterator to the first or end bit. */ /** @return The iterator to the first or end bit. */
NODISCARD FORCEINLINE constexpr Iterator Begin() { return Iterator(this, Impl, 0); } NODISCARD FORCEINLINE constexpr FIterator Begin() { return FIterator(this, Impl, 0); }
NODISCARD FORCEINLINE constexpr ConstIterator Begin() const { return ConstIterator(this, Impl, 0); } NODISCARD FORCEINLINE constexpr FConstIterator Begin() const { return FConstIterator(this, Impl, 0); }
NODISCARD FORCEINLINE constexpr Iterator End() { return Iterator(this, Impl, Num()); } NODISCARD FORCEINLINE constexpr FIterator End() { return FIterator(this, Impl, Num()); }
NODISCARD FORCEINLINE constexpr ConstIterator End() const { return ConstIterator(this, Impl, Num()); } NODISCARD FORCEINLINE constexpr FConstIterator End() const { return FConstIterator(this, Impl, Num()); }
/** @return The reverse iterator to the first or end bit. */ /** @return The reverse iterator to the first or end bit. */
NODISCARD FORCEINLINE constexpr ReverseIterator RBegin() { return ReverseIterator(End()); } NODISCARD FORCEINLINE constexpr FReverseIterator RBegin() { return FReverseIterator(End()); }
NODISCARD FORCEINLINE constexpr ConstReverseIterator RBegin() const { return ConstReverseIterator(End()); } NODISCARD FORCEINLINE constexpr FConstReverseIterator RBegin() const { return FConstReverseIterator(End()); }
NODISCARD FORCEINLINE constexpr ReverseIterator REnd() { return ReverseIterator(Begin()); } NODISCARD FORCEINLINE constexpr FReverseIterator REnd() { return FReverseIterator(Begin()); }
NODISCARD FORCEINLINE constexpr ConstReverseIterator REnd() const { return ConstReverseIterator(Begin()); } NODISCARD FORCEINLINE constexpr FConstReverseIterator REnd() const { return FConstReverseIterator(Begin()); }
/** @return The number of bits in the bitset. */ /** @return The number of bits in the bitset. */
NODISCARD FORCEINLINE constexpr size_t Num() const { return N; } NODISCARD FORCEINLINE constexpr size_t Num() const { return N; }
@ -460,17 +458,17 @@ public:
NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return Num() == 0; } NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return Num() == 0; }
/** @return true if the iterator is valid, false otherwise. */ /** @return true if the iterator is valid, false otherwise. */
NODISCARD FORCEINLINE constexpr bool IsValidIterator(ConstIterator Iter) const { return Begin() <= Iter && Iter <= End(); } NODISCARD FORCEINLINE constexpr bool IsValidIterator(FConstIterator Iter) const { return Begin() <= Iter && Iter <= End(); }
/** @return The reference to the requested bit. */ /** @return The reference to the requested bit. */
NODISCARD FORCEINLINE constexpr Reference operator[](size_t Index) { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return *(Begin() + Index); } NODISCARD FORCEINLINE constexpr FReference operator[](size_t Index) { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return *(Begin() + Index); }
NODISCARD FORCEINLINE constexpr ConstReference operator[](size_t Index) const { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return *(Begin() + Index); } NODISCARD FORCEINLINE constexpr FConstReference operator[](size_t Index) const { checkf(Index < Num(), TEXT("Read access violation. Please check IsValidIterator().")); return *(Begin() + Index); }
/** @return The reference to the first or last bit. */ /** @return The reference to the first or last bit. */
NODISCARD FORCEINLINE constexpr Reference Front() { return *Begin(); } NODISCARD FORCEINLINE constexpr FReference Front() { return *Begin(); }
NODISCARD FORCEINLINE constexpr ConstReference Front() const { return *Begin(); } NODISCARD FORCEINLINE constexpr FConstReference Front() const { return *Begin(); }
NODISCARD FORCEINLINE constexpr Reference Back() { return *(End() - 1); } NODISCARD FORCEINLINE constexpr FReference Back() { return *(End() - 1); }
NODISCARD FORCEINLINE constexpr ConstReference Back() const { return *(End() - 1); } NODISCARD FORCEINLINE constexpr FConstReference Back() const { return *(End() - 1); }
/** Overloads the GetTypeHash algorithm for TStaticBitset. */ /** Overloads the GetTypeHash algorithm for TStaticBitset. */
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TStaticBitset& A) NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash(const TStaticBitset& A)
@ -484,7 +482,7 @@ public:
Result = HashCombine(Result, GetTypeHash(A.Impl[Index])); Result = HashCombine(Result, GetTypeHash(A.Impl[Index]));
} }
const BlockType LastBlockBitmask = A.Num() % BlockWidth != 0 ? (1ull << A.Num() % BlockWidth) - 1 : -1; const FBlockType LastBlockBitmask = A.Num() % BlockWidth != 0 ? (1ull << A.Num() % BlockWidth) - 1 : -1;
return HashCombine(Result, GetTypeHash(A.Impl[A.NumBlocks() - 1] & LastBlockBitmask)); return HashCombine(Result, GetTypeHash(A.Impl[A.NumBlocks() - 1] & LastBlockBitmask));
} }
@ -496,21 +494,21 @@ public:
private: private:
BlockType Impl[N != 0 ? (N + BlockWidth - 1) / BlockWidth : 1]; FBlockType Impl[N != 0 ? (N + BlockWidth - 1) / BlockWidth : 1];
public: public:
class Reference final : private FSingleton class FReference final : private FSingleton
{ {
public: public:
FORCEINLINE constexpr Reference& operator=(bool InValue) { Data = (Data & ~Mask) | (InValue ? Mask : 0); return *this; } FORCEINLINE constexpr FReference& operator=(bool InValue) { Data = (Data & ~Mask) | (InValue ? Mask : 0); return *this; }
FORCEINLINE constexpr Reference& operator=(const Reference& InValue) { *this = static_cast<bool>(InValue); return *this; } FORCEINLINE constexpr FReference& operator=(const FReference& InValue) { *this = static_cast<bool>(InValue); return *this; }
FORCEINLINE constexpr Reference& operator&=(bool InValue) { Data &= InValue ? -1 : ~Mask; return *this; } FORCEINLINE constexpr FReference& operator&=(bool InValue) { Data &= InValue ? -1 : ~Mask; return *this; }
FORCEINLINE constexpr Reference& operator|=(bool InValue) { Data |= InValue ? Mask : 0; return *this; } FORCEINLINE constexpr FReference& operator|=(bool InValue) { Data |= InValue ? Mask : 0; return *this; }
FORCEINLINE constexpr Reference& operator^=(bool InValue) { *this = InValue ^ *this; return *this; } FORCEINLINE constexpr FReference& operator^=(bool InValue) { *this = InValue ^ *this; return *this; }
FORCEINLINE constexpr bool operator~() const { return !*this; } FORCEINLINE constexpr bool operator~() const { return !*this; }
@ -518,14 +516,14 @@ public:
private: private:
FORCEINLINE constexpr Reference(BlockType& InData, BlockType InMask) FORCEINLINE constexpr FReference(FBlockType& InData, FBlockType InMask)
: Data(InData), Mask(InMask) : Data(InData), Mask(InMask)
{ } { }
BlockType& Data; FBlockType& Data;
BlockType Mask; FBlockType Mask;
friend Iterator; friend FIterator;
}; };
@ -538,7 +536,7 @@ private:
public: public:
using ElementType = bool; using FElementType = bool;
FORCEINLINE constexpr TIteratorImpl() = default; FORCEINLINE constexpr TIteratorImpl() = default;
@ -561,8 +559,8 @@ private:
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TIteratorImpl& LHS, const TIteratorImpl& RHS) { check(LHS.Pointer == RHS.Pointer); return LHS.BitOffset <=> RHS.BitOffset; } NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TIteratorImpl& LHS, const TIteratorImpl& RHS) { check(LHS.Pointer == RHS.Pointer); return LHS.BitOffset <=> RHS.BitOffset; }
NODISCARD FORCEINLINE constexpr Reference operator*() const requires (!bConst) { CheckThis(true); return Reference(*(Pointer + BitOffset / BlockWidth), 1ull << BitOffset % BlockWidth); } NODISCARD FORCEINLINE constexpr FReference operator*() const requires (!bConst) { CheckThis(true); return FReference(*(Pointer + BitOffset / BlockWidth), 1ull << BitOffset % BlockWidth); }
NODISCARD FORCEINLINE constexpr ConstReference operator*() const requires ( bConst) { CheckThis(true); return (*(Pointer + BitOffset / BlockWidth) & (1ull << BitOffset % BlockWidth)); } NODISCARD FORCEINLINE constexpr FConstReference operator*() const requires ( bConst) { CheckThis(true); return (*(Pointer + BitOffset / BlockWidth) & (1ull << BitOffset % BlockWidth)); }
NODISCARD FORCEINLINE constexpr auto operator[](ptrdiff Index) const { TIteratorImpl Temp = *this + Index; return *Temp; } NODISCARD FORCEINLINE constexpr auto operator[](ptrdiff Index) const { TIteratorImpl Temp = *this + Index; return *Temp; }
@ -588,17 +586,17 @@ private:
const TStaticBitset* Owner = nullptr; const TStaticBitset* Owner = nullptr;
# endif # endif
using BlockPtr = TConditional<bConst, const BlockType*, BlockType*>; using FBlockPtr = TConditional<bConst, const FBlockType*, FBlockType*>;
BlockPtr Pointer = nullptr; FBlockPtr Pointer = nullptr;
size_t BitOffset = 0; size_t BitOffset = 0;
# if DO_CHECK # if DO_CHECK
FORCEINLINE constexpr TIteratorImpl(const TStaticBitset* InContainer, BlockPtr InPointer, size_t Offset) FORCEINLINE constexpr TIteratorImpl(const TStaticBitset* InContainer, FBlockPtr InPointer, size_t Offset)
: Owner(InContainer), Pointer(InPointer), BitOffset(Offset) : Owner(InContainer), Pointer(InPointer), BitOffset(Offset)
{ } { }
# else # else
FORCEINLINE constexpr TIteratorImpl(const TStaticBitset* InContainer, BlockPtr InPointer, size_t Offset) FORCEINLINE constexpr TIteratorImpl(const TStaticBitset* InContainer, FBlockPtr InPointer, size_t Offset)
: Pointer(InPointer), BitOffset(Offset) : Pointer(InPointer), BitOffset(Offset)
{ } { }
# endif # endif
@ -617,8 +615,6 @@ private:
}; };
#endif
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END

View File

@ -1,67 +0,0 @@
#pragma once
#include "CoreTypes.h"
#include "Iterator/Utility.h"
#include "Iterator/Sentinel.h"
#include "Iterator/ForwardIterator.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
#if PLATFORM_COMPILER_GCC
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnon-template-friend"
#endif
/** A concept specifies a type is a bidirectional iterator. Add the decrement operator to the forward iterator. */
template <typename I>
concept CBidirectionalIterator = CForwardIterator<I>
&& requires(I Iter) {
{ --Iter } -> CSameAs<I&>;
{ Iter-- } -> CSameAs<I >;
};
/**
* This is an example of a bidirectional iterator, indicate the traits that define a bidirectional iterator.
* Regardless of the order in which the increment and decrement operators are applied,
* the result is always the same if both operations are performed the same number of times.
*/
template <CReferenceable T>
struct IBidirectionalIterator /* : IForwardIterator<T> */
{
// ~Begin CForwardIterator.
using ElementType = TRemoveCVRef<T>;
IBidirectionalIterator();
IBidirectionalIterator(const IBidirectionalIterator&);
IBidirectionalIterator(IBidirectionalIterator&&);
IBidirectionalIterator* operator=(const IBidirectionalIterator&);
IBidirectionalIterator* operator=(IBidirectionalIterator&&);
friend bool operator==(const IBidirectionalIterator&, const IBidirectionalIterator&);
T operator*() const;
// ~End CForwardIterator.
IBidirectionalIterator& operator++(); // Also satisfies CForwardIterator.
IBidirectionalIterator& operator--();
IBidirectionalIterator operator++(int); // Also satisfies CForwardIterator.
IBidirectionalIterator operator--(int);
};
// Use IBidirectionalIterator<int> represents a bidirectional iterator.
static_assert(CBidirectionalIterator<IBidirectionalIterator<int&>>);
static_assert( COutputIterator<IBidirectionalIterator<int&>, int>);
#if PLATFORM_COMPILER_GCC
# pragma GCC diagnostic pop
#endif
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -1,98 +0,0 @@
#pragma once
#include "CoreTypes.h"
#include "Iterator/Utility.h"
#include "Iterator/Sentinel.h"
#include "Iterator/RandomAccessIterator.h"
#include "TypeTraits/TypeTraits.h"
#include "Memory/Address.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
#if PLATFORM_COMPILER_GCC
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnon-template-friend"
#endif
/**
* A concept specifies a type is a contiguous iterator.
* Add the operator-> to the random access iterator and requires the operator* returns a true reference type.
*/
template <typename I>
concept CContiguousIterator = CRandomAccessIterator<I> && CLValueReference<TIteratorReference<I>>
&& CSameAs<TIteratorElement<I>, TRemoveCVRef<TIteratorReference<I>>>
&& CSameAs<TIteratorPointer<I>, TAddPointer<TIteratorReference<I>>>
&& requires(I& Iter)
{
{ ToAddress(Iter) } -> CSameAs<TAddPointer<TIteratorReference<I>>>;
};
/** This is an example of a contiguous iterator, indicate the traits that define a contiguous iterator. */
template <CLValueReference T>
struct IContiguousIterator /* : IRandomAccessIterator<T> */
{
// ~Begin CRandomAccessIterator.
using ElementType = TRemoveCVRef<T>;
IContiguousIterator();
IContiguousIterator(const IContiguousIterator&);
IContiguousIterator(IContiguousIterator&&);
IContiguousIterator* operator=(const IContiguousIterator&);
IContiguousIterator* operator=(IContiguousIterator&&);
friend bool operator==(const IContiguousIterator&, const IContiguousIterator&);
friend strong_ordering operator<=>(const IContiguousIterator&, const IContiguousIterator&);
// ~End CRandomAccessIterator.
/**
* Dereference operator. See IForwardIterator.
* Specify, the return type must be a true reference type and refer to an element of a contiguous sequence, not a proxy class.
* Also satisfies CRandomAccessIterator.
*/
T operator*() const;
/** Indirection operator. Return the address of the element that the iterator is pointing to. */
TAddPointer<T> operator->() const;
// ~Begin CRandomAccessIterator.
T operator[](ptrdiff) const;
IContiguousIterator& operator++();
IContiguousIterator& operator--();
IContiguousIterator operator++(int);
IContiguousIterator operator--(int);
IContiguousIterator& operator+=(ptrdiff);
IContiguousIterator& operator-=(ptrdiff);
IContiguousIterator operator+(ptrdiff) const;
IContiguousIterator operator-(ptrdiff) const;
friend IContiguousIterator operator+(ptrdiff, const IContiguousIterator&);
friend ptrdiff operator-(const IContiguousIterator&, const IContiguousIterator&);
// ~End CRandomAccessIterator.
};
// Use IContiguousIterator<int> represents a contiguous iterator
static_assert(CContiguousIterator<IContiguousIterator<int&>>);
static_assert( COutputIterator<IContiguousIterator<int&>, int>);
// The int* is the most typical example of a contiguous iterator
static_assert(CContiguousIterator<int*>);
#if PLATFORM_COMPILER_GCC
# pragma GCC diagnostic pop
#endif
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -1,64 +0,0 @@
#pragma once
#include "CoreTypes.h"
#include "Iterator/Utility.h"
#include "Iterator/Sentinel.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
#if PLATFORM_COMPILER_GCC
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnon-template-friend"
#endif
/** A concept specifies a type is an input iterator. It is input iterator, incrementable, and sentinel for itself. */
template <typename I>
concept CForwardIterator = CInputIterator<I> && CIncrementable<I> && CSentinelFor<I, I>;
/** This is an example of a forward iterator, indicate the traits that define a forward iterator. */
template <CReferenceable T>
struct IForwardIterator /* : IInputIterator<T>, IIncrementable, ISentinelFor<IForwardIterator> */
{
// ~Begin CInputIterator.
using ElementType = TRemoveCVRef<T>;
// ~End CInputIterator.
// ~Begin CIncrementable and CSentinelFor<IForwardIterator>.
IForwardIterator();
IForwardIterator(const IForwardIterator&);
IForwardIterator(IForwardIterator&&); // Also satisfies IInputIterator.
IForwardIterator* operator=(const IForwardIterator&);
IForwardIterator* operator=(IForwardIterator&&); // Also satisfies IInputIterator.
friend bool operator==(const IForwardIterator&, const IForwardIterator&);
// ~End CIncrementable and CSentinelFor<IForwardIterator>.
// ~Begin CInputIterator.
T operator*() const; // Optional satisfies CIndirectlyWritable.
IForwardIterator& operator++(); // Also satisfies CIncrementable.
IForwardIterator operator++(int); // Also satisfies CIncrementable.
// ~End CInputIterator.
};
// Use IForwardIterator<int> represents a forward iterator.
static_assert(CForwardIterator<IForwardIterator<int&>>);
static_assert( COutputIterator<IForwardIterator<int&>, int>);
#if PLATFORM_COMPILER_GCC
# pragma GCC diagnostic pop
#endif
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -1,13 +0,0 @@
#pragma once
#include "CoreTypes.h"
#include "Iterator/Utility.h"
#include "Iterator/Sentinel.h"
#include "Iterator/ForwardIterator.h"
#include "Iterator/BidirectionalIterator.h"
#include "Iterator/RandomAccessIterator.h"
#include "Iterator/ContiguousIterator.h"
#include "Iterator/ReverseIterator.h"
#include "Iterator/MoveIterator.h"
#include "Iterator/CountedIterator.h"
#include "Iterator/InsertIterator.h"

View File

@ -1,93 +0,0 @@
#pragma once
#include "CoreTypes.h"
#include "Iterator/Utility.h"
#include "Iterator/Sentinel.h"
#include "Iterator/BidirectionalIterator.h"
#include "Miscellaneous/Compare.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
#if PLATFORM_COMPILER_GCC
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnon-template-friend"
#endif
/**
* A concept specifies a type is a random access iterator.
* Add the three-way comparison, addition, subtraction and subscript operators to the bidirectional iterator.
*/
template <typename I>
concept CRandomAccessIterator = CBidirectionalIterator<I> && CTotallyOrdered<I> && CSizedSentinelFor<I, I>
&& requires(I Iter, const I Jter, const ptrdiff N) {
{ Iter += N } -> CSameAs<I&>;
{ Jter + N } -> CSameAs<I >;
{ N + Jter } -> CSameAs<I >;
{ Iter -= N } -> CSameAs<I&>;
{ Jter - N } -> CSameAs<I >;
{ Jter[N] } -> CSameAs<TIteratorReference<I>>;
};
/** This is an example of a random access iterator, indicate the traits that define a random access iterator. */
template <CReferenceable T>
struct IRandomAccessIterator /* : IBidirectionalIterator<T>, ISizedSentinelFor<IRandomAccessIterator> */
{
// ~Begin CBidirectionalIterator.
using ElementType = TRemoveCVRef<T>;
// ~End CBidirectionalIterator.
// ~Begin CBidirectionalIterator and CSizedSentinelFor<IRandomAccessIterator>.
IRandomAccessIterator();
IRandomAccessIterator(const IRandomAccessIterator&);
IRandomAccessIterator(IRandomAccessIterator&&);
IRandomAccessIterator* operator=(const IRandomAccessIterator&);
IRandomAccessIterator* operator=(IRandomAccessIterator&&);
friend bool operator==(const IRandomAccessIterator&, const IRandomAccessIterator&);
// ~End CBidirectionalIterator and CSizedSentinelFor<IRandomAccessIterator>.
friend strong_ordering operator<=>(const IRandomAccessIterator&, const IRandomAccessIterator&);
T operator*() const; // Also satisfies CBidirectionalIterator.
T operator[](ptrdiff) const;
// ~Begin CBidirectionalIterator.
IRandomAccessIterator& operator++();
IRandomAccessIterator& operator--();
IRandomAccessIterator operator++(int);
IRandomAccessIterator operator--(int);
// ~End CBidirectionalIterator.
IRandomAccessIterator& operator+=(ptrdiff);
IRandomAccessIterator& operator-=(ptrdiff);
IRandomAccessIterator operator+(ptrdiff) const;
IRandomAccessIterator operator-(ptrdiff) const;
friend IRandomAccessIterator operator+(ptrdiff, const IRandomAccessIterator&);
friend ptrdiff operator-(const IRandomAccessIterator&, const IRandomAccessIterator&); // Also satisfies CSizedSentinelFor<IRandomAccessIterator>.
};
// Use IRandomAccessIterator<int> represents a random access iterator
static_assert(CRandomAccessIterator<IRandomAccessIterator<int&>>);
static_assert( COutputIterator<IRandomAccessIterator<int&>, int>);
#if PLATFORM_COMPILER_GCC
# pragma GCC diagnostic pop
#endif
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -0,0 +1,250 @@
#pragma once
#include "CoreTypes.h"
#include "Memory/Address.h"
#include "Iterators/Utility.h"
#include "Iterators/Sentinel.h"
#include "Miscellaneous/Compare.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
#if PLATFORM_COMPILER_GCC
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnon-template-friend"
#endif
/** A concept specifies a type is an input iterator. It is input iterator, incrementable, and sentinel for itself. */
template <typename I>
concept CForwardIterator = CInputIterator<I> && CIncrementable<I> && CSentinelFor<I, I>;
/** This is an example of a forward iterator, indicate the traits that define a forward iterator. */
template <CReferenceable T>
struct IForwardIterator /* : IInputIterator<T>, IIncrementable, ISentinelFor<IForwardIterator> */
{
// ~Begin CInputIterator.
using FElementType = TRemoveCVRef<T>;
// ~End CInputIterator.
// ~Begin CIncrementable and CSentinelFor<IForwardIterator>.
IForwardIterator();
IForwardIterator(const IForwardIterator&);
IForwardIterator(IForwardIterator&&); // Also satisfies IInputIterator.
IForwardIterator* operator=(const IForwardIterator&);
IForwardIterator* operator=(IForwardIterator&&); // Also satisfies IInputIterator.
friend bool operator==(const IForwardIterator&, const IForwardIterator&);
// ~End CIncrementable and CSentinelFor<IForwardIterator>.
// ~Begin CInputIterator.
T operator*() const; // Optional satisfies CIndirectlyWritable.
IForwardIterator& operator++(); // Also satisfies CIncrementable.
IForwardIterator operator++(int); // Also satisfies CIncrementable.
// ~End CInputIterator.
};
// Use IForwardIterator<int> represents a forward iterator.
static_assert(CForwardIterator<IForwardIterator<int&>>);
static_assert( COutputIterator<IForwardIterator<int&>, int>);
/** A concept specifies a type is a bidirectional iterator. Add the decrement operator to the forward iterator. */
template <typename I>
concept CBidirectionalIterator = CForwardIterator<I>
&& requires(I Iter) {
{ --Iter } -> CSameAs<I&>;
{ Iter-- } -> CSameAs<I >;
};
/**
* This is an example of a bidirectional iterator, indicate the traits that define a bidirectional iterator.
* Regardless of the order in which the increment and decrement operators are applied,
* the result is always the same if both operations are performed the same number of times.
*/
template <CReferenceable T>
struct IBidirectionalIterator /* : IForwardIterator<T> */
{
// ~Begin CForwardIterator.
using FElementType = TRemoveCVRef<T>;
IBidirectionalIterator();
IBidirectionalIterator(const IBidirectionalIterator&);
IBidirectionalIterator(IBidirectionalIterator&&);
IBidirectionalIterator* operator=(const IBidirectionalIterator&);
IBidirectionalIterator* operator=(IBidirectionalIterator&&);
friend bool operator==(const IBidirectionalIterator&, const IBidirectionalIterator&);
T operator*() const;
// ~End CForwardIterator.
IBidirectionalIterator& operator++(); // Also satisfies CForwardIterator.
IBidirectionalIterator& operator--();
IBidirectionalIterator operator++(int); // Also satisfies CForwardIterator.
IBidirectionalIterator operator--(int);
};
// Use IBidirectionalIterator<int> represents a bidirectional iterator.
static_assert(CBidirectionalIterator<IBidirectionalIterator<int&>>);
static_assert( COutputIterator<IBidirectionalIterator<int&>, int>);
/**
* A concept specifies a type is a random access iterator.
* Add the three-way comparison, addition, subtraction and subscript operators to the bidirectional iterator.
*/
template <typename I>
concept CRandomAccessIterator = CBidirectionalIterator<I> && CTotallyOrdered<I> && CSizedSentinelFor<I, I>
&& requires(I Iter, const I Jter, const ptrdiff N) {
{ Iter += N } -> CSameAs<I&>;
{ Jter + N } -> CSameAs<I >;
{ N + Jter } -> CSameAs<I >;
{ Iter -= N } -> CSameAs<I&>;
{ Jter - N } -> CSameAs<I >;
{ Jter[N] } -> CSameAs<TIteratorReference<I>>;
};
/** This is an example of a random access iterator, indicate the traits that define a random access iterator. */
template <CReferenceable T>
struct IRandomAccessIterator /* : IBidirectionalIterator<T>, ISizedSentinelFor<IRandomAccessIterator> */
{
// ~Begin CBidirectionalIterator.
using FElementType = TRemoveCVRef<T>;
// ~End CBidirectionalIterator.
// ~Begin CBidirectionalIterator and CSizedSentinelFor<IRandomAccessIterator>.
IRandomAccessIterator();
IRandomAccessIterator(const IRandomAccessIterator&);
IRandomAccessIterator(IRandomAccessIterator&&);
IRandomAccessIterator* operator=(const IRandomAccessIterator&);
IRandomAccessIterator* operator=(IRandomAccessIterator&&);
friend bool operator==(const IRandomAccessIterator&, const IRandomAccessIterator&);
// ~End CBidirectionalIterator and CSizedSentinelFor<IRandomAccessIterator>.
friend strong_ordering operator<=>(const IRandomAccessIterator&, const IRandomAccessIterator&);
T operator*() const; // Also satisfies CBidirectionalIterator.
T operator[](ptrdiff) const;
// ~Begin CBidirectionalIterator.
IRandomAccessIterator& operator++();
IRandomAccessIterator& operator--();
IRandomAccessIterator operator++(int);
IRandomAccessIterator operator--(int);
// ~End CBidirectionalIterator.
IRandomAccessIterator& operator+=(ptrdiff);
IRandomAccessIterator& operator-=(ptrdiff);
IRandomAccessIterator operator+(ptrdiff) const;
IRandomAccessIterator operator-(ptrdiff) const;
friend IRandomAccessIterator operator+(ptrdiff, const IRandomAccessIterator&);
friend ptrdiff operator-(const IRandomAccessIterator&, const IRandomAccessIterator&); // Also satisfies CSizedSentinelFor<IRandomAccessIterator>.
};
// Use IRandomAccessIterator<int> represents a random access iterator
static_assert(CRandomAccessIterator<IRandomAccessIterator<int&>>);
static_assert( COutputIterator<IRandomAccessIterator<int&>, int>);
/**
* A concept specifies a type is a contiguous iterator.
* Add the operator-> to the random access iterator and requires the operator* returns a true reference type.
*/
template <typename I>
concept CContiguousIterator = CRandomAccessIterator<I> && CLValueReference<TIteratorReference<I>>
&& CSameAs<TIteratorElement<I>, TRemoveCVRef<TIteratorReference<I>>>
&& CSameAs<TIteratorPointer<I>, TAddPointer<TIteratorReference<I>>>
&& requires(I& Iter)
{
{ ToAddress(Iter) } -> CSameAs<TAddPointer<TIteratorReference<I>>>;
};
/** This is an example of a contiguous iterator, indicate the traits that define a contiguous iterator. */
template <CLValueReference T>
struct IContiguousIterator /* : IRandomAccessIterator<T> */
{
// ~Begin CRandomAccessIterator.
using FElementType = TRemoveCVRef<T>;
IContiguousIterator();
IContiguousIterator(const IContiguousIterator&);
IContiguousIterator(IContiguousIterator&&);
IContiguousIterator* operator=(const IContiguousIterator&);
IContiguousIterator* operator=(IContiguousIterator&&);
friend bool operator==(const IContiguousIterator&, const IContiguousIterator&);
friend strong_ordering operator<=>(const IContiguousIterator&, const IContiguousIterator&);
// ~End CRandomAccessIterator.
/**
* Dereference operator. See IForwardIterator.
* Specify, the return type must be a true reference type and refer to an element of a contiguous sequence, not a proxy class.
* Also satisfies CRandomAccessIterator.
*/
T operator*() const;
/** Indirection operator. Return the address of the element that the iterator is pointing to. */
TAddPointer<T> operator->() const;
// ~Begin CRandomAccessIterator.
T operator[](ptrdiff) const;
IContiguousIterator& operator++();
IContiguousIterator& operator--();
IContiguousIterator operator++(int);
IContiguousIterator operator--(int);
IContiguousIterator& operator+=(ptrdiff);
IContiguousIterator& operator-=(ptrdiff);
IContiguousIterator operator+(ptrdiff) const;
IContiguousIterator operator-(ptrdiff) const;
friend IContiguousIterator operator+(ptrdiff, const IContiguousIterator&);
friend ptrdiff operator-(const IContiguousIterator&, const IContiguousIterator&);
// ~End CRandomAccessIterator.
};
// Use IContiguousIterator<int> represents a contiguous iterator
static_assert(CContiguousIterator<IContiguousIterator<int&>>);
static_assert( COutputIterator<IContiguousIterator<int&>, int>);
// The int* is the most typical example of a contiguous iterator
static_assert(CContiguousIterator<int*>);
#if PLATFORM_COMPILER_GCC
# pragma GCC diagnostic pop
#endif
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -1,11 +1,9 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Iterator/Utility.h" #include "Iterators/Utility.h"
#include "Iterator/Sentinel.h" #include "Iterators/Sentinel.h"
#include "Iterator/BidirectionalIterator.h" #include "Iterators/BasicIterator.h"
#include "Iterator/RandomAccessIterator.h"
#include "Iterator/ContiguousIterator.h"
#include "Miscellaneous/AssertionMacros.h" #include "Miscellaneous/AssertionMacros.h"
#include "Miscellaneous/Compare.h" #include "Miscellaneous/Compare.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
@ -18,8 +16,8 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_PRIVATE_BEGIN NAMESPACE_PRIVATE_BEGIN
template <typename T> class TCountedIteratorImpl { }; template <typename T> class TCountedIteratorImpl { };
template <CIndirectlyReadable T> class TCountedIteratorImpl<T> { public: using ElementType = TIteratorElement<T>; }; template <CIndirectlyReadable T> class TCountedIteratorImpl<T> { public: using FElementType = TIteratorElement<T>; };
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
@ -34,7 +32,7 @@ class TCountedIterator final : public NAMESPACE_PRIVATE::TCountedIteratorImpl<I>
{ {
public: public:
using IteratorType = I; using FIteratorType = I;
# if DO_CHECK # if DO_CHECK
FORCEINLINE constexpr TCountedIterator() requires (CDefaultConstructible<I>) : Length(1), MaxLength(0) { } FORCEINLINE constexpr TCountedIterator() requires (CDefaultConstructible<I>) : Length(1), MaxLength(0) { }
@ -48,7 +46,7 @@ public:
FORCEINLINE constexpr TCountedIterator& operator=(TCountedIterator&&) = default; FORCEINLINE constexpr TCountedIterator& operator=(TCountedIterator&&) = default;
FORCEINLINE constexpr ~TCountedIterator() = default; FORCEINLINE constexpr ~TCountedIterator() = default;
FORCEINLINE constexpr explicit TCountedIterator(IteratorType InValue, ptrdiff N) : Current(MoveTemp(InValue)) { check_code({ MaxLength = N; }); } FORCEINLINE constexpr explicit TCountedIterator(FIteratorType InValue, ptrdiff N) : Current(MoveTemp(InValue)), Length(N) { check_code({ MaxLength = N; }); }
template <CInputOrOutputIterator J> requires (!CSameAs<I, J> && CConstructibleFrom<I, const J&>) template <CInputOrOutputIterator J> requires (!CSameAs<I, J> && CConstructibleFrom<I, const J&>)
FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, I>) TCountedIterator(const TCountedIterator<J>& InValue) FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, I>) TCountedIterator(const TCountedIterator<J>& InValue)
@ -69,14 +67,12 @@ public:
} }
template <CInputOrOutputIterator J> requires (CCommonType<I, J>) 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>) 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 bool operator==(FDefaultSentinel) const& { return Num() == static_cast<ptrdiff>(0); }
NODISCARD FORCEINLINE constexpr strong_ordering operator<=>(FDefaultSentinel) const& { return static_cast<ptrdiff>(0) <=> Length; }
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() { CheckThis(true); return *GetBase(); } 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(); } NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() const requires (CDereferenceable<const I>) { CheckThis(true); return *GetBase(); }
@ -101,19 +97,19 @@ public:
NODISCARD friend FORCEINLINE constexpr TCountedIterator operator+(ptrdiff Offset, TCountedIterator Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; } NODISCARD friend FORCEINLINE constexpr TCountedIterator operator+(ptrdiff Offset, TCountedIterator Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; }
template <CInputOrOutputIterator J> requires (CCommonType<I, J>) 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-(const TCountedIterator& LHS, FDefaultSentinel) { LHS.CheckThis(); return -LHS.Num(); }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(FDefaultSentinel, const TCountedIterator& RHS) { RHS.CheckThis(); return RHS.Num(); } NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(FDefaultSentinel, const TCountedIterator& RHS) { RHS.CheckThis(); return RHS.Num(); }
NODISCARD FORCEINLINE constexpr const IteratorType& GetBase() const& { CheckThis(); return Current; } NODISCARD FORCEINLINE constexpr const FIteratorType& GetBase() const& { CheckThis(); return Current; }
NODISCARD FORCEINLINE constexpr IteratorType GetBase() && { CheckThis(); return MoveTemp(Current); } NODISCARD FORCEINLINE constexpr FIteratorType GetBase() && { CheckThis(); return MoveTemp(Current); }
NODISCARD FORCEINLINE constexpr ptrdiff Num() const { CheckThis(); return Length; } NODISCARD FORCEINLINE constexpr ptrdiff Num() const { CheckThis(); return Length; }
private: private:
IteratorType Current; FIteratorType Current;
ptrdiff Length; ptrdiff Length;
# if DO_CHECK # if DO_CHECK
ptrdiff MaxLength; ptrdiff MaxLength;
@ -125,9 +121,6 @@ private:
checkf(!(bExceptEnd && Length == static_cast<ptrdiff>(0)), TEXT("Read access violation. Please check Num().")); 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&>>>); static_assert( CInputIterator<TCountedIterator< IInputIterator<int&>>>);
@ -136,7 +129,7 @@ static_assert(CBidirectionalIterator<TCountedIterator<IBidirectionalIterator<int
static_assert( CRandomAccessIterator<TCountedIterator< IRandomAccessIterator<int&>>>); static_assert( CRandomAccessIterator<TCountedIterator< IRandomAccessIterator<int&>>>);
static_assert( CContiguousIterator<TCountedIterator< IContiguousIterator<int&>>>); static_assert( CContiguousIterator<TCountedIterator< IContiguousIterator<int&>>>);
//static_assert(COutputIterator<TCountedIterator<IOutputIterator<int&>>, int>); static_assert(COutputIterator<TCountedIterator<IOutputIterator<int&>>, int>);
static_assert(CSizedSentinelFor<TCountedIterator<IForwardIterator<int>>, TCountedIterator<IForwardIterator<int>>>); static_assert(CSizedSentinelFor<TCountedIterator<IForwardIterator<int>>, TCountedIterator<IForwardIterator<int>>>);

View File

@ -1,10 +1,13 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Iterator/Utility.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
#include "Templates/Noncopyable.h" #include "Iterators/Utility.h"
#include "Templates/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_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Redcraft)
@ -122,27 +125,77 @@ private:
static_assert(COutputIterator<TInsertIterator<void(*)(int)>, int>); 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 NAMESPACE_PRIVATE_END
/** Creates an iterator adapter inserted in the front of the container. */ /** Creates an iterator adapter inserted in the front of the container. */
template <typename C> template <typename C>
NODISCARD FORCEINLINE constexpr auto MakeFrontInserter(C& Container) 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. */ /** Creates an iterator adapter inserted in the back of the container. */
template <typename C> template <typename C>
NODISCARD FORCEINLINE constexpr auto MakeBackInserter(C& Container) 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. */ /** Creates an iterator adapter inserted in the container. */
template <typename C> template <typename C, typename I>
NODISCARD FORCEINLINE constexpr auto MakeInserter(C& Container, const typename C::ConstIterator& InIter) 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) NAMESPACE_MODULE_END(Utility)

View 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"

View File

@ -1,12 +1,9 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Iterator/Utility.h" #include "Iterators/Utility.h"
#include "Iterator/Sentinel.h" #include "Iterators/Sentinel.h"
#include "Iterator/ForwardIterator.h" #include "Iterators/BasicIterator.h"
#include "Iterator/BidirectionalIterator.h"
#include "Iterator/RandomAccessIterator.h"
#include "Iterator/ContiguousIterator.h"
#include "Miscellaneous/Compare.h" #include "Miscellaneous/Compare.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
@ -26,30 +23,31 @@ class TMoveIterator final
{ {
public: public:
using IteratorType = I; using FIteratorType = I;
using ElementType = TIteratorElement<I>; using FElementType = TIteratorElement<I>;
FORCEINLINE constexpr TMoveIterator() requires (CDefaultConstructible<I>) = default;
FORCEINLINE constexpr TMoveIterator() = default;
FORCEINLINE constexpr TMoveIterator(const TMoveIterator&) = default; FORCEINLINE constexpr TMoveIterator(const TMoveIterator&) = default;
FORCEINLINE constexpr TMoveIterator(TMoveIterator&&) = default; FORCEINLINE constexpr TMoveIterator(TMoveIterator&&) = default;
FORCEINLINE constexpr TMoveIterator& operator=(const TMoveIterator&) = default; FORCEINLINE constexpr TMoveIterator& operator=(const TMoveIterator&) = default;
FORCEINLINE constexpr TMoveIterator& operator=(TMoveIterator&&) = default; FORCEINLINE constexpr TMoveIterator& operator=(TMoveIterator&&) = default;
FORCEINLINE constexpr ~TMoveIterator() = default; FORCEINLINE constexpr ~TMoveIterator() = default;
FORCEINLINE constexpr explicit TMoveIterator(IteratorType InValue) : Current(MoveTemp(InValue)) { } FORCEINLINE constexpr explicit TMoveIterator(FIteratorType InValue) : Current(MoveTemp(InValue)) { }
template <CInputIterator J> requires (!CSameAs<I, J> && CConstructibleFrom<I, const J&>) template <CInputIterator J> requires (!CSameAs<I, J> && CConstructibleFrom<I, const J&>)
FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, I>) TMoveIterator(const TReverseIterator<J>& InValue) : Current(InValue.GetBase()) { } FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, I>) TMoveIterator(const TMoveIterator<J>& InValue) : Current(InValue.GetBase()) { }
template <CInputIterator J> requires (!CSameAs<I, J> && CConvertibleTo<const J&, I> && CAssignableFrom<I&, const J&>) template <CInputIterator J> requires (!CSameAs<I, J> && CConvertibleTo<const J&, I> && CAssignableFrom<I&, const J&>)
FORCEINLINE constexpr TMoveIterator& operator=(const TMoveIterator<J>& InValue) { Current = InValue.GetBase(); return *this; } FORCEINLINE constexpr TMoveIterator& operator=(const TMoveIterator<J>& InValue) { Current = InValue.GetBase(); return *this; }
template <CInputIterator J> requires (CSentinelFor<J, I>) template <CInputIterator J> requires (CEqualityComparable<I, J>)
NODISCARD friend FORCEINLINE constexpr bool operator==(const TMoveIterator& LHS, const TMoveIterator<J>& RHS) { return LHS.GetBase() == RHS.GetBase(); } 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>) 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()); } NODISCARD FORCEINLINE constexpr TIteratorRValueReference<I> operator*() const { return MoveTemp(*GetBase()); }
@ -70,14 +68,14 @@ public:
NODISCARD friend FORCEINLINE constexpr TMoveIterator operator+(ptrdiff Offset, const TMoveIterator& Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; } NODISCARD friend FORCEINLINE constexpr TMoveIterator operator+(ptrdiff Offset, const TMoveIterator& Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TMoveIterator& LHS, const TMoveIterator& RHS) requires (CRandomAccessIterator<I>) { return LHS.GetBase() - RHS.GetBase(); } NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TMoveIterator& LHS, const TMoveIterator& RHS) requires (CSizedSentinelFor<I, I>) { return LHS.GetBase() - RHS.GetBase(); }
NODISCARD FORCEINLINE constexpr const IteratorType& GetBase() const& { return Current; } NODISCARD FORCEINLINE constexpr const FIteratorType& GetBase() const& { return Current; }
NODISCARD FORCEINLINE constexpr IteratorType GetBase() && { return MoveTemp(Current); } NODISCARD FORCEINLINE constexpr FIteratorType GetBase() && { return MoveTemp(Current); }
private: private:
IteratorType Current; FIteratorType Current;
}; };
@ -99,7 +97,7 @@ class TMoveSentinel
{ {
public: public:
using SentinelType = S; using FSentinelType = S;
FORCEINLINE constexpr TMoveSentinel() = default; FORCEINLINE constexpr TMoveSentinel() = default;
FORCEINLINE constexpr TMoveSentinel(const TMoveSentinel&) = default; FORCEINLINE constexpr TMoveSentinel(const TMoveSentinel&) = default;
@ -108,7 +106,7 @@ public:
FORCEINLINE constexpr TMoveSentinel& operator=(TMoveSentinel&&) = default; FORCEINLINE constexpr TMoveSentinel& operator=(TMoveSentinel&&) = default;
FORCEINLINE constexpr ~TMoveSentinel() = default; FORCEINLINE constexpr ~TMoveSentinel() = default;
FORCEINLINE constexpr explicit TMoveSentinel(SentinelType InValue) : Last(InValue) { } FORCEINLINE constexpr explicit TMoveSentinel(FSentinelType InValue) : Last(InValue) { }
template <CSemiregular T> requires (!CSameAs<S, T> && CConstructibleFrom<S, const T&>) template <CSemiregular T> requires (!CSameAs<S, T> && CConstructibleFrom<S, const T&>)
FORCEINLINE constexpr explicit (!CConvertibleTo<const T&, S>) TMoveSentinel(const TMoveSentinel<T>& InValue) : Last(InValue.Last) { } FORCEINLINE constexpr explicit (!CConvertibleTo<const T&, S>) TMoveSentinel(const TMoveSentinel<T>& InValue) : Last(InValue.Last) { }
@ -125,12 +123,12 @@ public:
template <CInputIterator I> requires (CSizedSentinelFor<S, I>) template <CInputIterator I> requires (CSizedSentinelFor<S, I>)
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TMoveIterator<I>& Iter, const TMoveSentinel& Sentinel) { return Iter.GetBase() - Sentinel.GetBase(); } NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TMoveIterator<I>& Iter, const TMoveSentinel& Sentinel) { return Iter.GetBase() - Sentinel.GetBase(); }
NODISCARD FORCEINLINE constexpr const SentinelType& GetBase() const& { return Last; } NODISCARD FORCEINLINE constexpr const FSentinelType& GetBase() const& { return Last; }
NODISCARD FORCEINLINE constexpr SentinelType GetBase() && { return MoveTemp(Last); } NODISCARD FORCEINLINE constexpr FSentinelType GetBase() && { return MoveTemp(Last); }
private: private:
SentinelType Last; FSentinelType Last;
}; };

View File

@ -1,11 +1,9 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Iterator/Utility.h" #include "Iterators/Utility.h"
#include "Iterator/Sentinel.h" #include "Iterators/Sentinel.h"
#include "Iterator/BidirectionalIterator.h" #include "Iterators/BasicIterator.h"
#include "Iterator/RandomAccessIterator.h"
#include "Iterator/ContiguousIterator.h"
#include "Miscellaneous/Compare.h" #include "Miscellaneous/Compare.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
@ -25,9 +23,9 @@ class TReverseIterator final
{ {
public: public:
using IteratorType = I; using FIteratorType = I;
using ElementType = TIteratorElement<I>; using FElementType = TIteratorElement<I>;
FORCEINLINE constexpr TReverseIterator() = default; FORCEINLINE constexpr TReverseIterator() = default;
FORCEINLINE constexpr TReverseIterator(const TReverseIterator&) = default; FORCEINLINE constexpr TReverseIterator(const TReverseIterator&) = default;
@ -36,7 +34,7 @@ public:
FORCEINLINE constexpr TReverseIterator& operator=(TReverseIterator&&) = default; FORCEINLINE constexpr TReverseIterator& operator=(TReverseIterator&&) = default;
FORCEINLINE constexpr ~TReverseIterator() = default; FORCEINLINE constexpr ~TReverseIterator() = default;
FORCEINLINE constexpr explicit TReverseIterator(IteratorType InValue) : Current(InValue) { } FORCEINLINE constexpr explicit TReverseIterator(FIteratorType InValue) : Current(InValue) { }
template <CBidirectionalIterator J> requires (!CSameAs<I, J> && CConstructibleFrom<I, const J&>) template <CBidirectionalIterator J> requires (!CSameAs<I, J> && CConstructibleFrom<I, const J&>)
FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, I>) TReverseIterator(const TReverseIterator<J>& InValue) : Current(InValue.GetBase()) { } FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, I>) TReverseIterator(const TReverseIterator<J>& InValue) : Current(InValue.GetBase()) { }
@ -44,40 +42,40 @@ public:
template <CBidirectionalIterator J> requires (!CSameAs<I, J> && CConvertibleTo<const J&, I> && CAssignableFrom<I&, const J&>) template <CBidirectionalIterator J> requires (!CSameAs<I, J> && CConvertibleTo<const J&, I> && CAssignableFrom<I&, const J&>)
FORCEINLINE constexpr TReverseIterator& operator=(const TReverseIterator<J>& InValue) { Current = InValue.GetBase(); return *this; } FORCEINLINE constexpr TReverseIterator& operator=(const TReverseIterator<J>& InValue) { Current = InValue.GetBase(); return *this; }
template <CBidirectionalIterator J> requires (CSentinelFor<J, I>) template <CBidirectionalIterator J> requires (CEqualityComparable<I, J>)
NODISCARD friend FORCEINLINE constexpr bool operator==(const TReverseIterator& LHS, const TReverseIterator<J>& RHS) { return LHS.GetBase() == RHS.GetBase(); } NODISCARD friend FORCEINLINE constexpr bool operator==(const TReverseIterator& LHS, const TReverseIterator<J>& RHS) { return LHS.GetBase() == RHS.GetBase(); }
template <CBidirectionalIterator J> requires (CThreeWayComparable<I, J>) template <CBidirectionalIterator J> requires (CThreeWayComparable<I, J>)
NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<I, J> operator<=>(const TReverseIterator& LHS, const TReverseIterator<J>& RHS) { return RHS.GetBase() <=> LHS.GetBase(); } NODISCARD friend FORCEINLINE constexpr TCompareThreeWayResult<I, J> operator<=>(const TReverseIterator& LHS, const TReverseIterator<J>& RHS) { return RHS.GetBase() <=> LHS.GetBase(); }
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() const { IteratorType Temp = GetBase(); return *--Temp; } NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator*() const { FIteratorType Temp = GetBase(); return *--Temp; }
NODISCARD FORCEINLINE constexpr auto operator->() const requires (requires(const I Iter) { { ToAddress(Iter) } -> CSameAs<TIteratorPointer<I>>; }) { IteratorType Temp = GetBase(); return ToAddress(--Temp); } NODISCARD FORCEINLINE constexpr auto operator->() const requires (requires(const I Iter) { { ToAddress(Iter) } -> CSameAs<TIteratorPointer<I>>; }) { FIteratorType Temp = GetBase(); return ToAddress(--Temp); }
NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator[](ptrdiff Index) const requires (CRandomAccessIterator<I>) { return GetBase()[-Index - 1]; } NODISCARD FORCEINLINE constexpr TIteratorReference<I> operator[](ptrdiff Index) const requires (CRandomAccessIterator<I>) { return GetBase()[-Index - 1]; }
FORCEINLINE constexpr TReverseIterator& operator++() { --Current; return *this; } FORCEINLINE constexpr TReverseIterator& operator++() { --Current; return *this; }
FORCEINLINE constexpr TReverseIterator& operator--() { ++Current; return *this; } FORCEINLINE constexpr TReverseIterator& operator--() { ++Current; return *this; }
FORCEINLINE constexpr TReverseIterator operator++(int) { TReverseIterator Temp = *this; --Current; return Temp; } FORCEINLINE constexpr TReverseIterator operator++(int) { TReverseIterator Temp = *this; ++*this; return Temp; }
FORCEINLINE constexpr TReverseIterator operator--(int) { TReverseIterator Temp = *this; ++Current; return Temp; } FORCEINLINE constexpr TReverseIterator operator--(int) { TReverseIterator Temp = *this; --*this; return Temp; }
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; }
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; } NODISCARD friend FORCEINLINE constexpr TReverseIterator operator+(ptrdiff Offset, const TReverseIterator& Iter) requires (CRandomAccessIterator<I>) { return Iter + Offset; }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TReverseIterator& LHS, const TReverseIterator& RHS) requires (CRandomAccessIterator<I>) { return RHS.GetBase() - LHS.GetBase(); } NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const TReverseIterator& LHS, const TReverseIterator& RHS) requires (CSizedSentinelFor<I, I>) { return RHS.GetBase() - LHS.GetBase(); }
NODISCARD FORCEINLINE constexpr const IteratorType& GetBase() const& { return Current; } NODISCARD FORCEINLINE constexpr const FIteratorType& GetBase() const& { return Current; }
NODISCARD FORCEINLINE constexpr IteratorType GetBase() && { return MoveTemp(Current); } NODISCARD FORCEINLINE constexpr FIteratorType GetBase() && { return MoveTemp(Current); }
private: private:
IteratorType Current; FIteratorType Current;
}; };

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Iterator/Utility.h" #include "Iterators/Utility.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN

View File

@ -12,17 +12,17 @@ NAMESPACE_PRIVATE_BEGIN
template <typename T> using TWithReference = T&; template <typename T> using TWithReference = T&;
template <typename I> struct TIteratorElementImpl { }; template <typename I> struct TIteratorElementImpl { };
template <typename T> struct TIteratorElementImpl<T*> { using Type = TRemoveCV<T>; }; template <typename T> struct TIteratorElementImpl<T*> { using FType = TRemoveCV<T>; };
template <typename I> requires (requires { typename I::ElementType; }) template <typename I> requires (requires { typename I::FElementType; })
struct TIteratorElementImpl<I> { using Type = typename I::ElementType; }; struct TIteratorElementImpl<I> { using FType = typename I::FElementType; };
template <typename I> struct TIteratorPointerImpl { }; template <typename I> struct TIteratorPointerImpl { };
template <typename T> struct TIteratorPointerImpl<T*> { using Type = T*; }; template <typename T> struct TIteratorPointerImpl<T*> { using FType = T*; };
template <typename I> requires (requires(I& Iter) { { Iter.operator->() } -> CPointer; }) template <typename I> requires (requires(I& Iter) { { Iter.operator->() } -> CPointer; })
struct TIteratorPointerImpl<I> { using Type = decltype(DeclVal<I&>().operator->()); }; struct TIteratorPointerImpl<I> { using FType = decltype(DeclVal<I&>().operator->()); };
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
@ -33,10 +33,10 @@ template <typename T>
concept CDereferenceable = requires(T& A) { { *A } -> CReferenceable; }; concept CDereferenceable = requires(T& A) { { *A } -> CReferenceable; };
template <typename I> template <typename I>
using TIteratorElement = typename NAMESPACE_PRIVATE::TIteratorElementImpl<TRemoveCVRef<I>>::Type; using TIteratorElement = typename NAMESPACE_PRIVATE::TIteratorElementImpl<TRemoveCVRef<I>>::FType;
template <typename I> template <typename I>
using TIteratorPointer = typename NAMESPACE_PRIVATE::TIteratorPointerImpl<TRemoveCVRef<I>>::Type; using TIteratorPointer = typename NAMESPACE_PRIVATE::TIteratorPointerImpl<TRemoveCVRef<I>>::FType;
template <CReferenceable I> template <CReferenceable I>
using TIteratorReference = decltype(*DeclVal<I&>()); using TIteratorReference = decltype(*DeclVal<I&>());
@ -75,13 +75,13 @@ struct IIndirectlyReadable
* The element type of the indirectly readable type. * The element type of the indirectly readable type.
* It must be a non-const, non-volatile and non-reference type and can be referenced, i.e. not a void type. * It must be a non-const, non-volatile and non-reference type and can be referenced, i.e. not a void type.
*/ */
using ElementType = TRemoveCVRef<T>; using FElementType = TRemoveCVRef<T>;
/** /**
* Indirectly read the element from the indirectly readable type. * Indirectly read the element from the indirectly readable type.
* The return type may not be const ElementType&, this concept only requires that the return type * The return type may not be const FElementType&, this concept only requires that the return type
* and ElementType has some relationship, such as copy constructible to ElementType if the type is copyable. * and FElementType has some relationship, such as copy constructible to FElementType if the type is copyable.
* This means that returning a proxy class castable to ElementType is also valid. * This means that returning a proxy class castable to FElementType is also valid.
* If this is an iterator adaptor, use decltype(auto) to forward the return value. * If this is an iterator adaptor, use decltype(auto) to forward the return value.
*/ */
T operator*() const; T operator*() const;
@ -227,7 +227,7 @@ struct IInputIterator /* : IInputOrOutputIterator, IIndirectlyReadable */
{ {
// ~Begin CIndirectlyReadable. // ~Begin CIndirectlyReadable.
using ElementType = TRemoveCVRef<T>; using FElementType = TRemoveCVRef<T>;
// ~End CIndirectlyReadable. // ~End CIndirectlyReadable.

View File

@ -17,7 +17,7 @@ concept CAllocatableObject = CObject<T> && !CConst<T> && !CVolatile<T> && CDestr
template <typename A, typename T = int> template <typename A, typename T = int>
concept CAllocator = !CSameAs<A, FAllocatorInterface> && CAllocatableObject<T> concept CAllocator = !CSameAs<A, FAllocatorInterface> && CAllocatableObject<T>
&& requires (typename A::template ForElementType<T>& Allocator, T* InPtr, size_t Num, size_t NumAllocated) && requires (typename A::template TForElementType<T>& Allocator, T* InPtr, size_t Num, size_t NumAllocated)
{ {
{ Allocator.Allocate(Num) } -> CSameAs<T*>; { Allocator.Allocate(Num) } -> CSameAs<T*>;
{ Allocator.Deallocate(InPtr) } -> CSameAs<void>; { Allocator.Deallocate(InPtr) } -> CSameAs<void>;
@ -47,15 +47,15 @@ struct FAllocatorInterface
static constexpr bool bSupportsMultipleAllocation = true; static constexpr bool bSupportsMultipleAllocation = true;
template <CAllocatableObject T> template <CAllocatableObject T>
class ForElementType /*: private FSingleton*/ class TForElementType /*: private FSingleton*/
{ {
public: public:
ForElementType() = default; TForElementType() = default;
ForElementType(const ForElementType&) = delete; TForElementType(const TForElementType&) = delete;
ForElementType(ForElementType&&) = delete; TForElementType(TForElementType&&) = delete;
ForElementType& operator=(const ForElementType&) = delete; TForElementType& operator=(const TForElementType&) = delete;
ForElementType& operator=(ForElementType&&) = delete; TForElementType& operator=(TForElementType&&) = delete;
/** Allocates uninitialized storage. If 'InNum' is zero, return nullptr. */ /** Allocates uninitialized storage. If 'InNum' is zero, return nullptr. */
NODISCARD FORCEINLINE T* Allocate(size_t InNum) = delete; NODISCARD FORCEINLINE T* Allocate(size_t InNum) = delete;
@ -110,7 +110,7 @@ struct FAllocatorInterface
\ \
}; \ }; \
\ \
PREPROCESSOR_JOIN(T, Name)<typename Allocator::template ForElementType<Type>> Name; PREPROCESSOR_JOIN(T, Name)<typename Allocator::template TForElementType<Type>> Name;
/** This is heap allocator that calls Memory::Malloc() directly for memory allocation. */ /** This is heap allocator that calls Memory::Malloc() directly for memory allocation. */
struct FHeapAllocator struct FHeapAllocator
@ -118,15 +118,15 @@ struct FHeapAllocator
static constexpr bool bSupportsMultipleAllocation = true; static constexpr bool bSupportsMultipleAllocation = true;
template <CAllocatableObject T> template <CAllocatableObject T>
class ForElementType /*: private FSingleton*/ class TForElementType /*: private FSingleton*/
{ {
public: public:
ForElementType() = default; TForElementType() = default;
ForElementType(const ForElementType&) = delete; TForElementType(const TForElementType&) = delete;
ForElementType(ForElementType&&) = delete; TForElementType(TForElementType&&) = delete;
ForElementType& operator=(const ForElementType&) = delete; TForElementType& operator=(const TForElementType&) = delete;
ForElementType& operator=(ForElementType&&) = delete; TForElementType& operator=(TForElementType&&) = delete;
NODISCARD FORCEINLINE T* Allocate(size_t InNum) NODISCARD FORCEINLINE T* Allocate(size_t InNum)
{ {
@ -197,15 +197,15 @@ struct TInlineAllocator
static constexpr bool bSupportsMultipleAllocation = false; static constexpr bool bSupportsMultipleAllocation = false;
template <CAllocatableObject T> template <CAllocatableObject T>
class ForElementType /*: private FSingleton*/ class TForElementType /*: private FSingleton*/
{ {
public: public:
ForElementType() = default; TForElementType() = default;
ForElementType(const ForElementType&) = delete; TForElementType(const TForElementType&) = delete;
ForElementType(ForElementType&&) = delete; TForElementType(TForElementType&&) = delete;
ForElementType& operator=(const ForElementType&) = delete; TForElementType& operator=(const TForElementType&) = delete;
ForElementType& operator=(ForElementType&&) = delete; TForElementType& operator=(TForElementType&&) = delete;
NODISCARD FORCEINLINE T* Allocate(size_t InNum) NODISCARD FORCEINLINE T* Allocate(size_t InNum)
{ {
@ -279,15 +279,15 @@ struct FNullAllocator
static constexpr bool bSupportsMultipleAllocation = true; static constexpr bool bSupportsMultipleAllocation = true;
template <CAllocatableObject T> template <CAllocatableObject T>
class ForElementType /*: private FSingleton*/ class TForElementType /*: private FSingleton*/
{ {
public: public:
ForElementType() = default; TForElementType() = default;
ForElementType(const ForElementType&) = delete; TForElementType(const TForElementType&) = delete;
ForElementType(ForElementType&&) = delete; TForElementType(TForElementType&&) = delete;
ForElementType& operator=(const ForElementType&) = delete; TForElementType& operator=(const TForElementType&) = delete;
ForElementType& operator=(ForElementType&&) = delete; TForElementType& operator=(TForElementType&&) = delete;
NODISCARD FORCEINLINE T* Allocate(size_t InNum) { check_no_entry(); return nullptr; } NODISCARD FORCEINLINE T* Allocate(size_t InNum) { check_no_entry(); return nullptr; }

View File

@ -14,7 +14,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_PRIVATE_BEGIN NAMESPACE_PRIVATE_BEGIN
template <typename RT, typename ST> template <typename RT, typename ST>
using TRawPointer = TConditional<CVoid<RT>, typename TPointerTraits<TRemoveCVRef<ST>>::ElementType*, RT>; using TRawPointer = TConditional<CVoid<RT>, typename TPointerTraits<TRemoveCVRef<ST>>::FElementType*, RT>;
template <bool bEnableInput, typename RT, typename ST, typename... Ts> template <bool bEnableInput, typename RT, typename ST, typename... Ts>
class FInOutPtr final : private FSingleton class FInOutPtr final : private FSingleton
@ -57,7 +57,7 @@ NAMESPACE_PRIVATE_END
template <typename RT = void, typename ST, typename... Ts> requires ((CVoid<RT>) || (CPointer<RT>) template <typename RT = void, typename ST, typename... Ts> requires ((CVoid<RT>) || (CPointer<RT>)
&& (requires(NAMESPACE_PRIVATE::TRawPointer<RT, ST>* RPtr, ST& SPtr, Ts&&... Args) { SPtr.Reset(RPtr, Forward<Ts>(Args)...); }) && (requires(NAMESPACE_PRIVATE::TRawPointer<RT, ST>* RPtr, ST& SPtr, Ts&&... Args) { SPtr.Reset(RPtr, Forward<Ts>(Args)...); })
|| (CConstructibleFrom<ST, NAMESPACE_PRIVATE::TRawPointer<RT, ST>, Ts...> && CMoveAssignable<ST>) || (CConstructibleFrom<ST, NAMESPACE_PRIVATE::TRawPointer<RT, ST>, Ts...> && CMoveAssignable<ST>)
&& requires { typename TPointerTraits<TRemoveCV<ST>>::ElementType; }) && requires { typename TPointerTraits<TRemoveCV<ST>>::FElementType; })
auto OutPtr(ST& InPtr, Ts&&... Args) auto OutPtr(ST& InPtr, Ts&&... Args)
{ {
return NAMESPACE_PRIVATE::FInOutPtr<false, NAMESPACE_PRIVATE::TRawPointer<RT, ST>, ST, Ts...>(InPtr, Forward<Ts>(Args)...); return NAMESPACE_PRIVATE::FInOutPtr<false, NAMESPACE_PRIVATE::TRawPointer<RT, ST>, ST, Ts...>(InPtr, Forward<Ts>(Args)...);
@ -67,7 +67,7 @@ template <typename RT = void, typename ST, typename... Ts> requires ((CVoid<RT>)
&& (requires(NAMESPACE_PRIVATE::TRawPointer<RT, ST>* RPtr, ST& SPtr, Ts&&... Args) { SPtr.Reset(RPtr, Forward<Ts>(Args)...); }) && (requires(NAMESPACE_PRIVATE::TRawPointer<RT, ST>* RPtr, ST& SPtr, Ts&&... Args) { SPtr.Reset(RPtr, Forward<Ts>(Args)...); })
|| (CConstructibleFrom<ST, NAMESPACE_PRIVATE::TRawPointer<RT, ST>, Ts...> && CMoveAssignable<ST>) || (CConstructibleFrom<ST, NAMESPACE_PRIVATE::TRawPointer<RT, ST>, Ts...> && CMoveAssignable<ST>)
&& requires(ST& SPtr) { { SPtr.Release() } -> CConvertibleTo<NAMESPACE_PRIVATE::TRawPointer<RT, ST>>; } && requires(ST& SPtr) { { SPtr.Release() } -> CConvertibleTo<NAMESPACE_PRIVATE::TRawPointer<RT, ST>>; }
&& requires { typename TPointerTraits<TRemoveCV<ST>>::ElementType; }) && requires { typename TPointerTraits<TRemoveCV<ST>>::FElementType; })
auto InOutPtr(ST& InPtr, Ts&&... Args) auto InOutPtr(ST& InPtr, Ts&&... Args)
{ {
return NAMESPACE_PRIVATE::FInOutPtr<true, NAMESPACE_PRIVATE::TRawPointer<RT, ST>, ST, Ts...>(InPtr, Forward<Ts>(Args)...); return NAMESPACE_PRIVATE::FInOutPtr<true, NAMESPACE_PRIVATE::TRawPointer<RT, ST>, ST, Ts...>(InPtr, Forward<Ts>(Args)...);

View File

@ -19,10 +19,10 @@ struct TPointerTraits<T*>
{ {
static constexpr bool bIsPointer = true; static constexpr bool bIsPointer = true;
using PointerType = T*; using FPointerType = T*;
using ElementType = T; using FElementType = T;
static FORCEINLINE constexpr ElementType* ToAddress(PointerType InPtr) static FORCEINLINE constexpr FElementType* ToAddress(FPointerType InPtr)
{ {
return InPtr; return InPtr;
} }
@ -34,29 +34,29 @@ struct TPointerTraits<T(*)[]>
{ {
static constexpr bool bIsPointer = true; static constexpr bool bIsPointer = true;
using PointerType = T(*)[]; using FPointerType = T(*)[];
using ElementType = T; using FElementType = T;
static FORCEINLINE constexpr ElementType* ToAddress(PointerType InPtr) static FORCEINLINE constexpr FElementType* ToAddress(FPointerType InPtr)
{ {
return InPtr; return InPtr;
} }
}; };
/** A specialization of TPointerTraits is provided for pointer-like type. */ /** A specialization of TPointerTraits is provided for pointer-like type. */
#define DEFINE_TPointerTraits(TPtr) \ #define DEFINE_TPointerTraits(TPtr) \
template <typename T> \ template <typename T> \
struct TPointerTraits<TPtr<T>> \ struct TPointerTraits<TPtr<T>> \
{ \ { \
static constexpr bool bIsPointer = true; \ static constexpr bool bIsPointer = true; \
\ \
using PointerType = TPtr<T>; \ using FPointerType = TPtr<T>; \
using ElementType = TPtr<T>::ElementType; \ using FElementType = TPtr<T>::FElementType; \
\ \
static FORCEINLINE constexpr ElementType* ToAddress(const PointerType& InPtr) \ static FORCEINLINE constexpr FElementType* ToAddress(const FPointerType& InPtr) \
{ \ { \
return InPtr.Get(); \ return InPtr.Get(); \
} \ } \
}; };
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)

View File

@ -58,18 +58,18 @@ class alignas(Memory::ConstructiveInterference) FSharedController : private FSin
{ {
private: private:
using RefCounter = TAtomic<size_t>; using FRefCounter = TAtomic<size_t>;
// Ensure that counters are lock-free for performance. // Ensure that counters are lock-free for performance.
static_assert(RefCounter::bIsAlwaysLockFree); static_assert(FRefCounter::bIsAlwaysLockFree);
// When this count is zero the object is destroyed. // When this count is zero the object is destroyed.
// This count is the number of TSharedRef and TSharedPtr. // This count is the number of TSharedRef and TSharedPtr.
RefCounter SharedReferenceCount; FRefCounter SharedReferenceCount;
// When this count is zero the controller is destroyed. // When this count is zero the controller is destroyed.
// If SharedCounter is not zero this count is one more than the number of TWeakPtr. // If SharedCounter is not zero this count is one more than the number of TWeakPtr.
RefCounter WeakReferenceCount; FRefCounter WeakReferenceCount;
public: public:
@ -86,7 +86,7 @@ public:
virtual void DestroyThis() { delete this; } virtual void DestroyThis() { delete this; }
// Get shared reference count, no definite operation order. // Get shared reference count, no definite operation order.
FORCEINLINE RefCounter::ValueType GetSharedReferenceCount() FORCEINLINE FRefCounter::FValueType GetSharedReferenceCount()
{ {
// Get the shared reference count as EMemoryOrder::Relaxed, // Get the shared reference count as EMemoryOrder::Relaxed,
// since this count is for reference only and has no guarantees, // since this count is for reference only and has no guarantees,
@ -109,7 +109,7 @@ public:
// if the shared reference count is zero return false. // if the shared reference count is zero return false.
bool AddSharedReferenceIfUnexpired() bool AddSharedReferenceIfUnexpired()
{ {
RefCounter::ValueType OldSharedReferenceCount = GetSharedReferenceCount(); FRefCounter::FValueType OldSharedReferenceCount = GetSharedReferenceCount();
// We need to make sure we don't increase the reference count from zero to one. // We need to make sure we don't increase the reference count from zero to one.
while (true) while (true)
@ -131,7 +131,7 @@ public:
// where EMemoryOrder::Release ensures that the side effects of all operations // where EMemoryOrder::Release ensures that the side effects of all operations
// on the shared reference count of all threads are visible to this thread, // on the shared reference count of all threads are visible to this thread,
// preventing the shared reference count from actually going to zero. // preventing the shared reference count from actually going to zero.
RefCounter::ValueType OldSharedReferenceCount = SharedReferenceCount.FetchSub(1, EMemoryOrder::Release); FRefCounter::FValueType OldSharedReferenceCount = SharedReferenceCount.FetchSub(1, EMemoryOrder::Release);
// Make sure the shared reference count is not zero before. // Make sure the shared reference count is not zero before.
check(OldSharedReferenceCount != 0); check(OldSharedReferenceCount != 0);
@ -166,7 +166,7 @@ public:
{ {
// The use of EMemoryOrder is the same as in ReleaseSharedReference(). // The use of EMemoryOrder is the same as in ReleaseSharedReference().
RefCounter::ValueType OldWeakReferenceCount = WeakReferenceCount.FetchSub(1, EMemoryOrder::Release); FRefCounter::FValueType OldWeakReferenceCount = WeakReferenceCount.FetchSub(1, EMemoryOrder::Release);
check(OldWeakReferenceCount != 0); check(OldWeakReferenceCount != 0);
@ -407,12 +407,12 @@ struct FSharedHelper
if constexpr (CTWeakPtr<T> && CTWeakPtr<U>) if constexpr (CTWeakPtr<T> && CTWeakPtr<U>)
{ {
if (&InValue == &This) UNLIKELY return This; if (&InValue == &This) UNLIKELY return This;
if (This.Controller != nullptr) if (This.Controller != nullptr)
{ {
This.Controller->ReleaseWeakReference(); This.Controller->ReleaseWeakReference();
} }
This.Pointer = Exchange(InValue.Pointer, nullptr); This.Pointer = Exchange(InValue.Pointer, nullptr);
This.Controller = Exchange(InValue.Controller, nullptr); This.Controller = Exchange(InValue.Controller, nullptr);
} }
@ -522,7 +522,7 @@ protected:
private: private:
using SharedFromThisType = TSharedFromThis; using FSharedFromThisType = TSharedFromThis;
// Here it is updated by the private constructor of TSharedRef or TSharedPtr. // Here it is updated by the private constructor of TSharedRef or TSharedPtr.
mutable TWeakPtr<T> WeakThis; mutable TWeakPtr<T> WeakThis;
@ -539,12 +539,12 @@ class TSharedRef final
{ {
private: private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper; using FHelper = NAMESPACE_PRIVATE::FSharedHelper;
public: public:
using ElementType = T; using FElementType = T;
using WeakType = TWeakPtr<T>; using FWeakType = TWeakPtr<T>;
/** TSharedRef cannot be initialized by nullptr. */ /** TSharedRef cannot be initialized by nullptr. */
TSharedRef() = delete; TSharedRef() = delete;
@ -580,7 +580,7 @@ public:
Controller->AddSharedReference(); Controller->AddSharedReference();
} }
/** /**
* Aliasing constructor used to create a shared reference which shares its reference count with * Aliasing constructor used to create a shared reference which shares its reference count with
* another shared object, but pointing to a different object, typically a subobject. * another shared object, but pointing to a different object, typically a subobject.
@ -610,18 +610,18 @@ public:
FORCEINLINE ~TSharedRef() { Controller->ReleaseSharedReference(); } FORCEINLINE ~TSharedRef() { Controller->ReleaseSharedReference(); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TSharedRef& operator=(const TSharedRef& InValue) { return Helper::CopySharedReference(*this, InValue); } FORCEINLINE TSharedRef& operator=(const TSharedRef& InValue) { return FHelper::CopySharedReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedRef& operator=(const TSharedRef<U>& InValue) { return Helper::CopySharedReference(*this, InValue); } FORCEINLINE TSharedRef& operator=(const TSharedRef<U>& InValue) { return FHelper::CopySharedReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TSharedRef& operator=(TSharedRef&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); } FORCEINLINE TSharedRef& operator=(TSharedRef&& InValue) { return FHelper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedRef& operator=(TSharedRef<U>&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); } FORCEINLINE TSharedRef& operator=(TSharedRef<U>&& InValue) { return FHelper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Compares the pointer values of two TSharedRef. */ /** Compares the pointer values of two TSharedRef. */
template <typename U> requires (CEqualityComparable<T*, TRemoveExtent<U>*>) template <typename U> requires (CEqualityComparable<T*, TRemoveExtent<U>*>)
@ -732,15 +732,15 @@ private:
{ {
check(!((Pointer == nullptr) ^ (Controller == nullptr))); check(!((Pointer == nullptr) ^ (Controller == nullptr)));
if constexpr (CClass<T> && !CVolatile<T> && requires { typename T::SharedFromThisType; }) if constexpr (CClass<T> && !CVolatile<T> && requires { typename T::FSharedFromThisType; })
{ {
using SharedFromThisType = T::SharedFromThisType; using FSharedFromThisType = typename T::FSharedFromThisType;
if constexpr (CDerivedFrom<T, SharedFromThisType>) if constexpr (CDerivedFrom<T, FSharedFromThisType>)
{ {
if (Pointer != nullptr) if (Pointer != nullptr)
{ {
const SharedFromThisType& SharedFromThis = *Pointer; const FSharedFromThisType& SharedFromThis = *Pointer;
checkf(!SharedFromThis.DoesSharedInstanceExist(), TEXT("This object is incorrectly managed by multiple TSharedRef or TSharedPtr.")); checkf(!SharedFromThis.DoesSharedInstanceExist(), TEXT("This object is incorrectly managed by multiple TSharedRef or TSharedPtr."));
SharedFromThis.WeakThis = ConstCast<TRemoveCV<T>>(*this); SharedFromThis.WeakThis = ConstCast<TRemoveCV<T>>(*this);
} }
@ -762,12 +762,12 @@ class TSharedRef<T[]> final
{ {
private: private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper; using FHelper = NAMESPACE_PRIVATE::FSharedHelper;
public: public:
using ElementType = T; using FElementType = T;
using WeakType = TWeakPtr<T>; using FWeakType = TWeakPtr<T>;
/** TSharedRef cannot be initialized by nullptr. */ /** TSharedRef cannot be initialized by nullptr. */
TSharedRef() = delete; TSharedRef() = delete;
@ -835,18 +835,18 @@ public:
FORCEINLINE ~TSharedRef() { Controller->ReleaseSharedReference(); } FORCEINLINE ~TSharedRef() { Controller->ReleaseSharedReference(); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TSharedRef& operator=(const TSharedRef& InValue) { return Helper::CopySharedReference(*this, InValue); } FORCEINLINE TSharedRef& operator=(const TSharedRef& InValue) { return FHelper::CopySharedReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>) template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedRef& operator=(const TSharedRef<U>& InValue) { return Helper::CopySharedReference(*this, InValue); } FORCEINLINE TSharedRef& operator=(const TSharedRef<U>& InValue) { return FHelper::CopySharedReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TSharedRef& operator=(TSharedRef&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); } FORCEINLINE TSharedRef& operator=(TSharedRef&& InValue) { return FHelper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>) template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedRef& operator=(TSharedRef<U>&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); } FORCEINLINE TSharedRef& operator=(TSharedRef<U>&& InValue) { return FHelper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Compares the pointer values of two TSharedRef. */ /** Compares the pointer values of two TSharedRef. */
template <typename U> requires (CEqualityComparable<T*, TRemoveExtent<U>*>) template <typename U> requires (CEqualityComparable<T*, TRemoveExtent<U>*>)
@ -972,13 +972,13 @@ class TSharedPtr final
{ {
private: private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper; using FHelper = NAMESPACE_PRIVATE::FSharedHelper;
public: public:
using ElementType = T; using FElementType = T;
using WeakType = TWeakPtr<T>; using FWeakType = TWeakPtr<T>;
/** Constructs an empty shared pointer. */ /** Constructs an empty shared pointer. */
FORCEINLINE constexpr TSharedPtr() : Pointer(nullptr), Controller(nullptr) { } FORCEINLINE constexpr TSharedPtr() : Pointer(nullptr), Controller(nullptr) { }
@ -1073,22 +1073,22 @@ public:
FORCEINLINE ~TSharedPtr() { if (Controller != nullptr) Controller->ReleaseSharedReference(); } FORCEINLINE ~TSharedPtr() { if (Controller != nullptr) Controller->ReleaseSharedReference(); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TSharedPtr& operator=(const TSharedPtr& InValue) { return Helper::CopySharedReference(*this, InValue); } FORCEINLINE TSharedPtr& operator=(const TSharedPtr& InValue) { return FHelper::CopySharedReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedPtr& operator=(const TSharedPtr<U>& InValue) { return Helper::CopySharedReference(*this, InValue); } FORCEINLINE TSharedPtr& operator=(const TSharedPtr<U>& InValue) { return FHelper::CopySharedReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedPtr& operator=(const TSharedRef<U>& InValue) { return Helper::CopySharedReference(*this, InValue); } FORCEINLINE TSharedPtr& operator=(const TSharedRef<U>& InValue) { return FHelper::CopySharedReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TSharedPtr& operator=(TSharedPtr&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); } FORCEINLINE TSharedPtr& operator=(TSharedPtr&& InValue) { return FHelper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TSharedPtr& operator=(TSharedPtr<U>&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); } FORCEINLINE TSharedPtr& operator=(TSharedPtr<U>&& InValue) { return FHelper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
template <typename U, typename E> requires (CConvertibleTo<U*, T*> && !CArray<U> && (CDestructible<E> || CLValueReference<E>)) template <typename U, typename E> requires (CConvertibleTo<U*, T*> && !CArray<U> && (CDestructible<E> || CLValueReference<E>))
@ -1200,14 +1200,14 @@ private:
T* Pointer; T* Pointer;
NAMESPACE_PRIVATE::FSharedController* Controller; NAMESPACE_PRIVATE::FSharedController* Controller;
FORCEINLINE TSharedPtr(const TWeakPtr<T>& InValue) FORCEINLINE TSharedPtr(const TWeakPtr<T>& InValue)
{ {
const bool bIsUnexpired = InValue.Controller != nullptr && InValue.Controller->AddSharedReferenceIfUnexpired(); const bool bIsUnexpired = InValue.Controller != nullptr && InValue.Controller->AddSharedReferenceIfUnexpired();
Pointer = bIsUnexpired ? InValue.Pointer : nullptr; Pointer = bIsUnexpired ? InValue.Pointer : nullptr;
Controller = bIsUnexpired ? InValue.Controller : nullptr; Controller = bIsUnexpired ? InValue.Controller : nullptr;
} }
FORCEINLINE TSharedPtr(T* InPtr, NAMESPACE_PRIVATE::FSharedController* InController) FORCEINLINE TSharedPtr(T* InPtr, NAMESPACE_PRIVATE::FSharedController* InController)
@ -1215,15 +1215,15 @@ private:
{ {
check(!((Pointer == nullptr) ^ (Controller == nullptr))); check(!((Pointer == nullptr) ^ (Controller == nullptr)));
if constexpr (CClass<T> && !CVolatile<T> && requires { typename T::SharedFromThisType; }) if constexpr (CClass<T> && !CVolatile<T> && requires { typename T::FSharedFromThisType; })
{ {
using SharedFromThisType = T::SharedFromThisType; using FSharedFromThisType = typename T::FSharedFromThisType;
if constexpr (CDerivedFrom<T, SharedFromThisType>) if constexpr (CDerivedFrom<T, FSharedFromThisType>)
{ {
if (Pointer != nullptr) if (Pointer != nullptr)
{ {
const SharedFromThisType& SharedFromThis = *Pointer; const FSharedFromThisType& SharedFromThis = *Pointer;
checkf(!SharedFromThis.DoesSharedInstanceExist(), TEXT("This object is incorrectly managed by multiple TSharedRef or TSharedPtr.")); checkf(!SharedFromThis.DoesSharedInstanceExist(), TEXT("This object is incorrectly managed by multiple TSharedRef or TSharedPtr."));
SharedFromThis.WeakThis = ConstCast<TRemoveCV<T>>(*this); SharedFromThis.WeakThis = ConstCast<TRemoveCV<T>>(*this);
} }
@ -1245,12 +1245,12 @@ class TSharedPtr<T[]> final
{ {
private: private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper; using FHelper = NAMESPACE_PRIVATE::FSharedHelper;
public: public:
using ElementType = T; using FElementType = T;
using WeakType = TWeakPtr<T>; using FWeakType = TWeakPtr<T>;
/** Constructs an empty shared pointer. */ /** Constructs an empty shared pointer. */
FORCEINLINE constexpr TSharedPtr() : Pointer(nullptr), Controller(nullptr) { } FORCEINLINE constexpr TSharedPtr() : Pointer(nullptr), Controller(nullptr) { }
@ -1348,22 +1348,22 @@ public:
FORCEINLINE ~TSharedPtr() { if (Controller != nullptr) Controller->ReleaseSharedReference(); } FORCEINLINE ~TSharedPtr() { if (Controller != nullptr) Controller->ReleaseSharedReference(); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TSharedPtr& operator=(const TSharedPtr& InValue) { return Helper::CopySharedReference(*this, InValue); } FORCEINLINE TSharedPtr& operator=(const TSharedPtr& InValue) { return FHelper::CopySharedReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>) template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedPtr& operator=(const TSharedPtr<U>& InValue) { return Helper::CopySharedReference(*this, InValue); } FORCEINLINE TSharedPtr& operator=(const TSharedPtr<U>& InValue) { return FHelper::CopySharedReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>) template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedPtr& operator=(const TSharedRef<U>& InValue) { return Helper::CopySharedReference(*this, InValue); } FORCEINLINE TSharedPtr& operator=(const TSharedRef<U>& InValue) { return FHelper::CopySharedReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TSharedPtr& operator=(TSharedPtr&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); } FORCEINLINE TSharedPtr& operator=(TSharedPtr&& InValue) { return FHelper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>) template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TSharedPtr& operator=(TSharedPtr<U>&& InValue) { return Helper::MoveSharedReference(*this, MoveTemp(InValue)); } FORCEINLINE TSharedPtr& operator=(TSharedPtr<U>&& InValue) { return FHelper::MoveSharedReference(*this, MoveTemp(InValue)); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
template <typename U, typename E> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U> && (CDestructible<E> || CLValueReference<E>)) template <typename U, typename E> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U> && (CDestructible<E> || CLValueReference<E>))
@ -1482,7 +1482,7 @@ private:
Pointer = bIsUnexpired ? InValue.Pointer : nullptr; Pointer = bIsUnexpired ? InValue.Pointer : nullptr;
Controller = bIsUnexpired ? InValue.Controller : nullptr; Controller = bIsUnexpired ? InValue.Controller : nullptr;
} }
FORCEINLINE TSharedPtr(T* InPtr, NAMESPACE_PRIVATE::FSharedController* InController) FORCEINLINE TSharedPtr(T* InPtr, NAMESPACE_PRIVATE::FSharedController* InController)
@ -1505,11 +1505,11 @@ class TWeakPtr final
{ {
private: private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper; using FHelper = NAMESPACE_PRIVATE::FSharedHelper;
public: public:
using ElementType = T; using FElementType = T;
/** Constructs an empty TWeakPtr */ /** Constructs an empty TWeakPtr */
FORCEINLINE constexpr TWeakPtr() : Pointer(nullptr), Controller(nullptr) { } FORCEINLINE constexpr TWeakPtr() : Pointer(nullptr), Controller(nullptr) { }
@ -1542,7 +1542,7 @@ public:
/** Move constructors. Moves a TWeakPtr instance from 'InValue' into this. */ /** Move constructors. Moves a TWeakPtr instance from 'InValue' into this. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE constexpr TWeakPtr(TWeakPtr<U>&& InValue) : Pointer(Exchange(InValue.Pointer, nullptr)), Controller(Exchange(InValue.Controller, nullptr)) { } FORCEINLINE constexpr TWeakPtr(TWeakPtr<U>&& InValue) : Pointer(Exchange(InValue.Pointer, nullptr)), Controller(Exchange(InValue.Controller, nullptr)) { }
/** Constructs a weak pointer from a shared reference. */ /** Constructs a weak pointer from a shared reference. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE constexpr TWeakPtr(const TSharedRef<U>& InValue) : Pointer(InValue.Pointer), Controller(InValue.Controller) FORCEINLINE constexpr TWeakPtr(const TSharedRef<U>& InValue) : Pointer(InValue.Pointer), Controller(InValue.Controller)
@ -1564,26 +1564,26 @@ public:
FORCEINLINE ~TWeakPtr() { if (Controller != nullptr) Controller->ReleaseWeakReference(); } FORCEINLINE ~TWeakPtr() { if (Controller != nullptr) Controller->ReleaseWeakReference(); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TWeakPtr& operator=(const TWeakPtr& InValue) { return Helper::CopyWeakReference(*this, InValue); } FORCEINLINE TWeakPtr& operator=(const TWeakPtr& InValue) { return FHelper::CopyWeakReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TWeakPtr<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); } FORCEINLINE TWeakPtr& operator=(const TWeakPtr<U>& InValue) { return FHelper::CopyWeakReference(*this, InValue); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
FORCEINLINE TWeakPtr& operator=(TWeakPtr&& InValue) { return Helper::MoveWeakReference(*this, MoveTemp(InValue)); } FORCEINLINE TWeakPtr& operator=(TWeakPtr&& InValue) { return FHelper::MoveWeakReference(*this, MoveTemp(InValue)); }
/** Replaces the managed object with the one managed by 'InValue'. */ /** Replaces the managed object with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TWeakPtr& operator=(TWeakPtr<U>&& InValue) { return Helper::MoveWeakReference(*this, MoveTemp(InValue)); } FORCEINLINE TWeakPtr& operator=(TWeakPtr<U>&& InValue) { return FHelper::MoveWeakReference(*this, MoveTemp(InValue)); }
/** Assignment operator sets this weak pointer from a shared reference. */ /** Assignment operator sets this weak pointer from a shared reference. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TSharedRef<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); } FORCEINLINE TWeakPtr& operator=(const TSharedRef<U>& InValue) { return FHelper::CopyWeakReference(*this, InValue); }
/** Assignment operator sets this weak pointer from a shared pointer. */ /** Assignment operator sets this weak pointer from a shared pointer. */
template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>) template <typename U> requires (CConvertibleTo<U*, T*> && !CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TSharedPtr<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); } FORCEINLINE TWeakPtr& operator=(const TSharedPtr<U>& InValue) { return FHelper::CopyWeakReference(*this, InValue); }
/** Effectively the same as calling Reset(). */ /** Effectively the same as calling Reset(). */
FORCEINLINE TWeakPtr& operator=(nullptr_t) { Reset(); return *this; } FORCEINLINE TWeakPtr& operator=(nullptr_t) { Reset(); return *this; }
@ -1639,11 +1639,11 @@ class TWeakPtr<T[]> final
{ {
private: private:
using Helper = NAMESPACE_PRIVATE::FSharedHelper; using FHelper = NAMESPACE_PRIVATE::FSharedHelper;
public: public:
using ElementType = T; using FElementType = T;
/** Constructs an empty TWeakPtr */ /** Constructs an empty TWeakPtr */
FORCEINLINE constexpr TWeakPtr() : Pointer(nullptr), Controller(nullptr) { } FORCEINLINE constexpr TWeakPtr() : Pointer(nullptr), Controller(nullptr) { }
@ -1698,26 +1698,26 @@ public:
FORCEINLINE ~TWeakPtr() { if (Controller != nullptr) Controller->ReleaseWeakReference(); } FORCEINLINE ~TWeakPtr() { if (Controller != nullptr) Controller->ReleaseWeakReference(); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TWeakPtr& operator=(const TWeakPtr& InValue) { return Helper::CopyWeakReference(*this, InValue); } FORCEINLINE TWeakPtr& operator=(const TWeakPtr& InValue) { return FHelper::CopyWeakReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>) template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TWeakPtr<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); } FORCEINLINE TWeakPtr& operator=(const TWeakPtr<U>& InValue) { return FHelper::CopyWeakReference(*this, InValue); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
FORCEINLINE TWeakPtr& operator=(TWeakPtr&& InValue) { return Helper::MoveWeakReference(*this, MoveTemp(InValue)); } FORCEINLINE TWeakPtr& operator=(TWeakPtr&& InValue) { return FHelper::MoveWeakReference(*this, MoveTemp(InValue)); }
/** Replaces the managed array with the one managed by 'InValue'. */ /** Replaces the managed array with the one managed by 'InValue'. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>) template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TWeakPtr& operator=(TWeakPtr<U>&& InValue) { return Helper::MoveWeakReference(*this, MoveTemp(InValue)); } FORCEINLINE TWeakPtr& operator=(TWeakPtr<U>&& InValue) { return FHelper::MoveWeakReference(*this, MoveTemp(InValue)); }
/** Assignment operator sets this weak pointer from a shared reference. */ /** Assignment operator sets this weak pointer from a shared reference. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>) template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TSharedRef<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); } FORCEINLINE TWeakPtr& operator=(const TSharedRef<U>& InValue) { return FHelper::CopyWeakReference(*this, InValue); }
/** Assignment operator sets this weak pointer from a shared pointer. */ /** Assignment operator sets this weak pointer from a shared pointer. */
template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>) template <typename U> requires (CConvertibleTo<TRemoveExtent<U>(*)[], T(*)[]> && CArray<U>)
FORCEINLINE TWeakPtr& operator=(const TSharedPtr<U>& InValue) { return Helper::CopyWeakReference(*this, InValue); } FORCEINLINE TWeakPtr& operator=(const TSharedPtr<U>& InValue) { return FHelper::CopyWeakReference(*this, InValue); }
/** Effectively the same as calling Reset(). */ /** Effectively the same as calling Reset(). */
FORCEINLINE TWeakPtr& operator=(nullptr_t) { Reset(); return *this; } FORCEINLINE TWeakPtr& operator=(nullptr_t) { Reset(); return *this; }

View File

@ -179,8 +179,8 @@ class TUniqueRef final : private FSingleton
{ {
public: public:
using ElementType = T; using FElementType = T;
using DeleterType = E; using FDeleterType = E;
/** TUniqueRef cannot be initialized by nullptr. */ /** TUniqueRef cannot be initialized by nullptr. */
TUniqueRef() = delete; TUniqueRef() = delete;
@ -308,8 +308,8 @@ class TUniqueRef<T[], E> final : private FSingleton
{ {
public: public:
using ElementType = T; using FElementType = T;
using DeleterType = E; using FDeleterType = E;
/** TUniqueRef cannot be initialized by nullptr. */ /** TUniqueRef cannot be initialized by nullptr. */
TUniqueRef() = delete; TUniqueRef() = delete;
@ -439,8 +439,8 @@ class TUniquePtr final : private FNoncopyable
{ {
public: public:
using ElementType = T; using FElementType = T;
using DeleterType = E; using FDeleterType = E;
/** Constructs a TUniquePtr that owns nothing. Value-initializes the stored pointer and the stored deleter. */ /** Constructs a TUniquePtr that owns nothing. Value-initializes the stored pointer and the stored deleter. */
FORCEINLINE constexpr TUniquePtr() requires(CDefaultConstructible<E> && !CPointer<E>) : Storage(nullptr) { } FORCEINLINE constexpr TUniquePtr() requires(CDefaultConstructible<E> && !CPointer<E>) : Storage(nullptr) { }
@ -585,8 +585,8 @@ class TUniquePtr<T[], E> final : private FNoncopyable
{ {
public: public:
using ElementType = T; using FElementType = T;
using DeleterType = E; using FDeleterType = E;
/** Constructs a TUniquePtr that owns nothing. Value-initializes the stored pointer and the stored deleter. */ /** Constructs a TUniquePtr that owns nothing. Value-initializes the stored pointer and the stored deleter. */
FORCEINLINE constexpr TUniquePtr() requires(CDefaultConstructible<E> && !CPointer<E>) : Storage(nullptr) { } FORCEINLINE constexpr TUniquePtr() requires(CDefaultConstructible<E> && !CPointer<E>) : Storage(nullptr) { }

View File

@ -42,6 +42,8 @@ NAMESPACE_PRIVATE_END
# define DO_CHECK 0 # define DO_CHECK 0
#endif #endif
// ReSharper disable CppInconsistentNaming
#define always_check(InExpr) RS_CHECK_IMPL(InExpr) #define always_check(InExpr) RS_CHECK_IMPL(InExpr)
#define always_checkf(InExpr, InFormat, ...) RS_CHECK_F_IMPL(InExpr, InFormat, ##__VA_ARGS__) #define always_checkf(InExpr, InFormat, ...) RS_CHECK_F_IMPL(InExpr, InFormat, ##__VA_ARGS__)
#define always_check_no_entry() always_checkf(false, "Enclosing block should never be called.") #define always_check_no_entry() always_checkf(false, "Enclosing block should never be called.")
@ -77,6 +79,8 @@ NAMESPACE_PRIVATE_END
#endif #endif
// ReSharper restore CppInconsistentNaming
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END

View 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

View File

@ -12,17 +12,21 @@ NAMESPACE_MODULE_BEGIN(Utility)
// The result of the three-way comparison operator is the built-in type of the compiler, which is directly introduced here // The result of the three-way comparison operator is the built-in type of the compiler, which is directly introduced here
typedef NAMESPACE_STD::partial_ordering partial_ordering; // ReSharper disable CppInconsistentNaming
typedef NAMESPACE_STD::weak_ordering weak_ordering;
typedef NAMESPACE_STD::strong_ordering strong_ordering; using partial_ordering = NAMESPACE_STD::partial_ordering;
using weak_ordering = NAMESPACE_STD::weak_ordering;
using strong_ordering = NAMESPACE_STD::strong_ordering;
// ReSharper restore CppInconsistentNaming
NAMESPACE_PRIVATE_BEGIN NAMESPACE_PRIVATE_BEGIN
template<int32> struct TCommonComparisonCategoryBasic { }; template<int32> struct TCommonComparisonCategoryBasic { };
template<> struct TCommonComparisonCategoryBasic<0> { using Type = strong_ordering; }; template<> struct TCommonComparisonCategoryBasic<0> { using FType = strong_ordering; };
template<> struct TCommonComparisonCategoryBasic<2> { using Type = partial_ordering; }; template<> struct TCommonComparisonCategoryBasic<2> { using FType = partial_ordering; };
template<> struct TCommonComparisonCategoryBasic<4> { using Type = weak_ordering; }; template<> struct TCommonComparisonCategoryBasic<4> { using FType = weak_ordering; };
template<> struct TCommonComparisonCategoryBasic<6> { using Type = partial_ordering; }; template<> struct TCommonComparisonCategoryBasic<6> { using FType = partial_ordering; };
template <typename... Ts> template <typename... Ts>
struct TCommonComparisonCategoryImpl struct TCommonComparisonCategoryImpl
@ -32,13 +36,13 @@ struct TCommonComparisonCategoryImpl
CSameAs<Ts, weak_ordering > ? 4u : CSameAs<Ts, weak_ordering > ? 4u :
CSameAs<Ts, partial_ordering> ? 2u : 1u CSameAs<Ts, partial_ordering> ? 2u : 1u
) )
)> )>
{ }; { };
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
template <typename... Ts> template <typename... Ts>
using TCommonComparisonCategory = typename NAMESPACE_PRIVATE::TCommonComparisonCategoryImpl<Ts...>::Type; using TCommonComparisonCategory = typename NAMESPACE_PRIVATE::TCommonComparisonCategoryImpl<Ts...>::FType;
template <typename T, typename OrderingType> template <typename T, typename OrderingType>
concept CThreeWayComparesAs = CSameAs<TCommonComparisonCategory<T, OrderingType>, OrderingType>; concept CThreeWayComparesAs = CSameAs<TCommonComparisonCategory<T, OrderingType>, OrderingType>;

View 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

View File

@ -1,226 +0,0 @@
#pragma once
#include "CoreTypes.h"
#include "Memory/Address.h"
#include "Templates/Utility.h"
#include "Miscellaneous/Iterator.h"
#include "Miscellaneous/Compare.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
/** An iterator that always points to the same value. */
template <typename T> requires (CDestructible<T> || CLValueReference<T>)
class TConstantIterator final
{
public:
using ElementType = TRemoveCV<T>;
FORCEINLINE constexpr TConstantIterator() = default;
FORCEINLINE constexpr ~TConstantIterator() = default;
template <typename U = T> requires (!CSameAs<TConstantIterator, TRemoveCVRef<U>> && CConstructibleFrom<T, U&&>)
FORCEINLINE constexpr explicit TConstantIterator(U&& InValue) : Value(Forward<U>(InValue)) { }
template <typename U> requires (CConstructibleFrom<T, const U&>)
FORCEINLINE constexpr explicit (!CConvertibleTo<const U&, T>) TConstantIterator(const TConstantIterator<U>& InValue) : Value(InValue.Value) { }
template <typename U> requires (CConstructibleFrom<T, U&&>)
FORCEINLINE constexpr explicit (!CConvertibleTo<U&&, T>) TConstantIterator(TConstantIterator<U>&& InValue) : Value(MoveTemp(InValue.Value)) { }
FORCEINLINE constexpr TConstantIterator(const TConstantIterator&) requires (CCopyConstructible<T>) = default;
FORCEINLINE constexpr TConstantIterator(TConstantIterator&&) requires (CMoveConstructible<T>) = default;
template <typename U> requires (CConvertibleTo<const U&, T> && CAssignableFrom<T&, const U&>)
FORCEINLINE constexpr TConstantIterator& operator=(const TConstantIterator<U>& InValue) { Value = InValue.Value; return *this; }
template <typename U> requires (CConvertibleTo<U&&, T> && CAssignableFrom<T&, U&&>)
FORCEINLINE constexpr TConstantIterator& operator=(TConstantIterator<U>&& InValue) { Value = MoveTemp(InValue.Value); return *this; }
FORCEINLINE constexpr TConstantIterator& operator=(const TConstantIterator&) requires (CCopyAssignable<T>) = default;
FORCEINLINE constexpr TConstantIterator& operator=(TConstantIterator&&) requires (CMoveAssignable<T>) = default;
NODISCARD FORCEINLINE constexpr const T& operator*() const { return Value; }
NODISCARD FORCEINLINE constexpr const T* operator->() const { return AddressOf(Value); }
FORCEINLINE constexpr TConstantIterator& operator++() { return *this; }
FORCEINLINE constexpr void operator++(int) { }
private:
T Value;
template <typename U> requires (CDestructible<U> || CLValueReference<U>)
friend class TConstantIterator;
};
static_assert(CInputIterator<TConstantIterator<int>>);
/** An iterator that always points to the same value. */
template <typename T>
class TConstantIterator<T&> final
{
public:
using ElementType = TRemoveCV<T>;
FORCEINLINE constexpr TConstantIterator() = default;
FORCEINLINE constexpr TConstantIterator(const TConstantIterator&) = default;
FORCEINLINE constexpr TConstantIterator(TConstantIterator&&) = default;
FORCEINLINE constexpr TConstantIterator& operator=(const TConstantIterator&) = default;
FORCEINLINE constexpr TConstantIterator& operator=(TConstantIterator&&) = default;
FORCEINLINE constexpr ~TConstantIterator() = default;
FORCEINLINE constexpr explicit TConstantIterator(const T& InValue) : Ptr(AddressOf(InValue)) { }
FORCEINLINE constexpr explicit TConstantIterator(const T&& InValue) = delete;
template <typename U> requires (CConvertibleTo<U*, T*>)
FORCEINLINE constexpr TConstantIterator(const TConstantIterator<U>& InValue) : Ptr(InValue.Ptr) { }
template <typename U> requires (CConvertibleTo<U*, T*>)
FORCEINLINE constexpr TConstantIterator& operator=(const TConstantIterator<U>& InValue) { Ptr = InValue.Ptr; return *this; }
NODISCARD FORCEINLINE constexpr const T& operator*() const { return *Ptr; }
NODISCARD FORCEINLINE constexpr const T* operator->() const { return Ptr; }
FORCEINLINE constexpr TConstantIterator& operator++() { return *this; }
FORCEINLINE constexpr void operator++(int) { }
private:
const T* Ptr;
template <typename U> requires (CDestructible<U> || CLValueReference<U>)
friend class TConstantIterator;
};
static_assert(CInputIterator<TConstantIterator<int&>>);
/** An iterator adapter specialization that tracks the distance of a constant iterator to the end of the range. */
template <typename T> requires (CDestructible<T> || CLValueReference<T>)
class TCountedIterator<TConstantIterator<T>> final
{
public:
using IteratorType = TConstantIterator<T>;
using ElementType = typename TConstantIterator<T>::ElementType;
# if DO_CHECK
FORCEINLINE constexpr TCountedIterator() requires (CDefaultConstructible<IteratorType>) : Length(1), MaxLength(0) { }
# else
FORCEINLINE constexpr TCountedIterator() requires (CDefaultConstructible<IteratorType>) = default;
# endif
FORCEINLINE constexpr TCountedIterator(const TCountedIterator&) = default;
FORCEINLINE constexpr TCountedIterator(TCountedIterator&&) = default;
FORCEINLINE constexpr TCountedIterator& operator=(const TCountedIterator&) = default;
FORCEINLINE constexpr TCountedIterator& operator=(TCountedIterator&&) = default;
FORCEINLINE constexpr ~TCountedIterator() = default;
template <typename U = IteratorType> requires (!CSameAs<TCountedIterator, TRemoveCVRef<U>> && CConstructibleFrom<IteratorType, U>)
FORCEINLINE constexpr explicit TCountedIterator(U&& InValue, ptrdiff N) : Current(Forward<U>(InValue)), Length(N) { check_code({ MaxLength = N; }); }
template <CInputOrOutputIterator J> requires (!CSameAs<IteratorType, J> && CConstructibleFrom<IteratorType, const J&>)
FORCEINLINE constexpr explicit (!CConvertibleTo<const J&, IteratorType>) TCountedIterator(const TCountedIterator<J>& InValue) : Current(InValue.Current), Length(InValue.Num()) { check_code({ MaxLength = InValue.MaxLength; }); }
template <CInputOrOutputIterator J> requires (!CSameAs<IteratorType, J> && CConstructibleFrom<IteratorType, J>)
FORCEINLINE constexpr explicit (!CConvertibleTo<J&&, IteratorType>) TCountedIterator(TCountedIterator<J>&& InValue) : Current(MoveTemp(InValue).Current), Length(InValue.Num()) { check_code({ MaxLength = InValue.MaxLength; }); }
template <CInputOrOutputIterator J> requires (!CSameAs<IteratorType, J> && CConvertibleTo<const J&, IteratorType> && CAssignableFrom<IteratorType&, const J&>)
FORCEINLINE constexpr TCountedIterator& operator=(const TCountedIterator<J>& InValue) { Current = InValue.Current; Length = InValue.Num(); check_code({ MaxLength = InValue.MaxLength; }); return *this; }
template <CInputOrOutputIterator J> requires (!CSameAs<IteratorType, J> && CConvertibleTo<J&&, IteratorType> && CAssignableFrom<IteratorType&, J&&>)
FORCEINLINE constexpr TCountedIterator& operator=(TCountedIterator<J>&& InValue) { Current = MoveTemp(InValue).Current; Length = InValue.Num(); check_code({ MaxLength = InValue.MaxLength; }); return *this; }
template <CCommonType<IteratorType> J>
NODISCARD friend FORCEINLINE constexpr bool operator==(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Length == RHS.Length; }
template <CCommonType<IteratorType> J>
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const TCountedIterator& LHS, const TCountedIterator<J>& RHS) { return LHS.Length <=> RHS.Length; }
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 const TRemoveReference<T>& operator*() const { CheckThis(true ); return *Current; }
NODISCARD FORCEINLINE constexpr const TRemoveReference<T>* operator->() const { CheckThis(false); return ToAddress(Current); }
NODISCARD FORCEINLINE constexpr const TRemoveReference<T>& operator[](ptrdiff) const { return *this; }
FORCEINLINE constexpr TCountedIterator& operator++() { --Length; CheckThis(); return *this; }
FORCEINLINE constexpr TCountedIterator& operator--() { ++Length; CheckThis(); return *this; }
FORCEINLINE constexpr TCountedIterator operator++(int) { TCountedIterator Temp = *this; --Length; CheckThis(); return Temp; }
FORCEINLINE constexpr TCountedIterator operator--(int) { TCountedIterator Temp = *this; ++Length; CheckThis(); return Temp; }
FORCEINLINE constexpr TCountedIterator& operator+=(ptrdiff Offset) { Length -= Offset; CheckThis(); return *this; }
FORCEINLINE constexpr TCountedIterator& operator-=(ptrdiff Offset) { Length += Offset; CheckThis(); return *this; }
NODISCARD friend FORCEINLINE constexpr TCountedIterator operator+(TCountedIterator Iter, ptrdiff Offset) { TCountedIterator Temp = Iter; Temp += Offset; return Temp; }
NODISCARD friend FORCEINLINE constexpr TCountedIterator operator+(ptrdiff Offset, TCountedIterator Iter) { TCountedIterator Temp = Iter; Temp += Offset; return Temp; }
NODISCARD FORCEINLINE constexpr TCountedIterator operator-(ptrdiff Offset) const { TCountedIterator Temp = *this; Temp -= Offset; return Temp; }
template <CCommonType<IteratorType> 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, FDefaultSentinel) { LHS.CheckThis(); return -LHS.Num(); }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(FDefaultSentinel, const TCountedIterator& RHS) { RHS.CheckThis(); return RHS.Num(); }
NODISCARD FORCEINLINE constexpr const IteratorType& GetBase() const& { CheckThis(); return Current; }
NODISCARD FORCEINLINE constexpr IteratorType GetBase() && { CheckThis(); return MoveTemp(Current); }
NODISCARD FORCEINLINE constexpr ptrdiff Num() const { CheckThis(); return Length; }
private:
IteratorType Current;
ptrdiff Length;
# if DO_CHECK
ptrdiff MaxLength;
# endif
FORCEINLINE void CheckThis(bool bExceptEnd = false) const
{
checkf(static_cast<ptrdiff>(0) <= Length && Length <= MaxLength, TEXT("Read access violation. Please check Num()."));
checkf(!(bExceptEnd && Length == static_cast<ptrdiff>(0)), TEXT("Read access violation. Please check Num()."));
}
template <CInputOrOutputIterator J>
friend class TCountedIterator;
};
static_assert(CRandomAccessIterator<TCountedIterator<TConstantIterator<int>>>);
static_assert(CSizedSentinelFor<FDefaultSentinel, TCountedIterator<TConstantIterator<int>>>);
template <typename T> requires (CDestructible<T> || CLValueReference<T>)
NODISCARD FORCEINLINE constexpr auto MakeConstantIterator(T&& Value)
{
return TConstantIterator<T>(Forward<T>(Value));
}
template <typename T> requires (CDestructible<T> || CLValueReference<T>)
NODISCARD FORCEINLINE constexpr auto MakeCountedConstantIterator(T&& Value, ptrdiff N)
{
return TCountedIterator<TConstantIterator<T>>(MakeConstantIterator(Forward<T>(Value)), N);
}
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -1,77 +0,0 @@
#pragma once
#include "CoreTypes.h"
#include "Templates/TypeHash.h"
#include "TypeTraits/Swappable.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
/** @return The pointer to the container element storage. */
template <typename T> requires (requires(T&& Container) { { Container.GetData() } -> CPointer; })
FORCEINLINE constexpr auto GetData(T&& Container)
{
return Container.GetData();
}
/** Overloads the GetData algorithm for arrays. */
template <typename T, size_t N> FORCEINLINE constexpr T* GetData( T(& Container)[N]) { return Container; }
template <typename T, size_t N> FORCEINLINE constexpr T* GetData( T(&& Container)[N]) { return Container; }
template <typename T, size_t N> FORCEINLINE constexpr const T* GetData(const T(& Container)[N]) { return Container; }
template <typename T, size_t N> FORCEINLINE constexpr const T* GetData(const T(&& Container)[N]) { return Container; }
/** Overloads the GetData algorithm for initializer_list. */
template <typename T>
FORCEINLINE constexpr const T* GetData(initializer_list<T> Container)
{
return Container.begin();
}
/** @return The number of elements in the container. */
template <typename T> requires (requires(T&& Container) { { Container.Num() } -> CConvertibleTo<size_t>; })
FORCEINLINE constexpr auto GetNum(T&& Container)
{
return Container.Num();
}
/** Overloads the GetNum algorithm for arrays. */
template <typename T, size_t N> FORCEINLINE constexpr size_t GetNum( T(& )[N]) { return N; }
template <typename T, size_t N> FORCEINLINE constexpr size_t GetNum( T(&&)[N]) { return N; }
template <typename T, size_t N> FORCEINLINE constexpr size_t GetNum(const T(& )[N]) { return N; }
template <typename T, size_t N> FORCEINLINE constexpr size_t GetNum(const T(&&)[N]) { return N; }
/** Overloads the GetNum algorithm for initializer_list. */
template <typename T>
FORCEINLINE constexpr size_t GetNum(initializer_list<T> Container)
{
return Container.size();
}
/** Overloads the Swap algorithm for arrays. */
template <typename T, size_t N> requires (CSwappable<TRemoveAllExtents<T>>)
FORCEINLINE constexpr void Swap(T(&A)[N], T(&B)[N])
{
for (size_t Index = 0; Index < N; ++Index)
{
Swap(A[Index], B[Index]);
}
}
/** Overloads the GetTypeHash algorithm for arrays. */
template <typename T, size_t N> requires (CHashable<TRemoveAllExtents<T>>)
FORCEINLINE constexpr size_t GetTypeHash(T(&A)[N])
{
size_t Result = 3516520171;
for (size_t Index = 0; Index < N; ++Index)
{
Result = HashCombine(Result, GetTypeHash(A[Index]));
}
return Result;
}
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -9,6 +9,8 @@ NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_MODULE_BEGIN(Utility)
// ReSharper disable CppInconsistentNaming
#define NORETURN [[noreturn]] #define NORETURN [[noreturn]]
#define CARRIES_DEPENDENCY [[carries_dependency]] #define CARRIES_DEPENDENCY [[carries_dependency]]
#define DEPRECATED(Message) [[deprecated(Message)]] #define DEPRECATED(Message) [[deprecated(Message)]]
@ -42,6 +44,8 @@ using type_info = NAMESPACE_STD::type_info;
template <typename T> template <typename T>
using initializer_list = NAMESPACE_STD::initializer_list<T>; using initializer_list = NAMESPACE_STD::initializer_list<T>;
// ReSharper restore CppInconsistentNaming
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END

View 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

View File

@ -1,200 +0,0 @@
#pragma once
#include "CoreTypes.h"
#include "Iterator/Iterator.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
template <typename I>
using TIteratorElementType = TIteratorElement<I>;
template <typename I>
using TIteratorPointerType = TIteratorPointer<I>;
template <CReferenceable I>
using TIteratorReferenceType = TIteratorReference<I>;
template <CReferenceable I> requires (requires(I& Iter) { { MoveTemp(*Iter) } -> CReferenceable; })
using TIteratorRValueReferenceType = TIteratorRValueReference<I>;
NAMESPACE_BEGIN(Iteration)
/** Increments given iterator 'Iter' by 'N' elements. */
template <CInputIterator 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;
}
}
/** @return The number of hops from 'First' to 'Last'. */
template <CInputIterator I, CSentinelFor<I> S>
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 'N'-th successor of iterator 'Iter'. */
template <CInputIterator I>
FORCEINLINE constexpr I Next(I Iter, TMakeUnsigned<ptrdiff> N = 1)
{
Iteration::Advance(Iter, N);
return Iter;
}
/** @return The 'N'-th predecessor of iterator 'Iter'. */
template <CBidirectionalIterator I>
FORCEINLINE constexpr I Prev(I Iter, TMakeUnsigned<ptrdiff> N = 1)
{
Iteration::Advance(Iter, -N);
return Iter;
}
NAMESPACE_END(Iteration)
template <CIndirectlyReadable J, CIndirectlyWritable<TIteratorReferenceType<J>> I>
FORCEINLINE void IndirectlyCopy(I&& Iter, J&& Jter)
{
*Iter = *Jter;
}
template <CIndirectlyReadable J, CIndirectlyWritable<TIteratorRValueReferenceType<J>> I>
FORCEINLINE void IndirectlyMove(I&& Iter, J&& Jter)
{
*Iter = MoveTemp(*Jter);
}
template <CIndirectlyReadable I, CIndirectlyReadable J> requires (CSwappable<TIteratorReferenceType<I>, TIteratorReferenceType<J>>)
FORCEINLINE void IndirectlySwap(I&& Iter, J&& Jter)
{
Swap(*Iter, *Jter);
}
template <typename I, typename J = I>
concept CIndirectlyCopyable = requires(const I Iter, const J Jter) { IndirectlyCopy(Iter, Jter); };
template <typename I, typename J = I>
concept CIndirectlyMovable = requires(const I Iter, const J Jter) { IndirectlyMove(Iter, Jter); };
template <typename I, typename J = I>
concept CIndirectlySwappable = CIndirectlyReadable<I> && CIndirectlyReadable<J>
&& requires(const I Iter, const J Jter)
{
IndirectlySwap(Iter, Iter);
IndirectlySwap(Jter, Jter);
IndirectlySwap(Iter, Jter);
IndirectlySwap(Jter, Iter);
};
NAMESPACE_BEGIN(Iteration)
/** @return The iterator to the beginning of a container. */
template <typename T> requires (requires(T&& Container) { { Container.Begin() } -> CForwardIterator; })
FORCEINLINE constexpr auto Begin(T&& Container)
{
return Container.Begin();
}
/** Overloads the Begin algorithm for arrays. */
template <typename T, size_t N> FORCEINLINE constexpr T* Begin( T(& Container)[N]) { return Container; }
template <typename T, size_t N> FORCEINLINE constexpr T* Begin( T(&& Container)[N]) { return Container; }
template <typename T, size_t N> FORCEINLINE constexpr const T* Begin(const T(& Container)[N]) { return Container; }
template <typename T, size_t N> FORCEINLINE constexpr const T* Begin(const T(&& Container)[N]) { return Container; }
/** Overloads the Begin algorithm for initializer_list. */
template <typename T>
FORCEINLINE constexpr auto Begin(initializer_list<T> Container)
{
return Container.begin();
}
/** @return The iterator to the end of a container. */
template <typename T> requires (requires(T&& Container) { { Container.End() } -> CForwardIterator; })
FORCEINLINE constexpr auto End(T&& Container)
{
return Container.End();
}
/** Overloads the End algorithm for arrays. */
template <typename T, size_t N> FORCEINLINE constexpr T* End( T(& Container)[N]) { return Container + N; }
template <typename T, size_t N> FORCEINLINE constexpr T* End( T(&& Container)[N]) { return Container + N; }
template <typename T, size_t N> FORCEINLINE constexpr const T* End(const T(& Container)[N]) { return Container + N; }
template <typename T, size_t N> FORCEINLINE constexpr const T* End(const T(&& Container)[N]) { return Container + N; }
/** Overloads the End algorithm for initializer_list. */
template <typename T>
FORCEINLINE constexpr auto End(initializer_list<T> Container)
{
return Container.end();
}
/** @return The reverse iterator to the beginning of a container. */
template <typename T> requires (requires(T&& Container) { { Container.RBegin() } -> CForwardIterator; })
FORCEINLINE constexpr auto RBegin(T&& Container)
{
return Container.RBegin();
}
/** Overloads the RBegin algorithm for arrays. */
template <typename T, size_t N> FORCEINLINE constexpr auto RBegin( T(& Container)[N]) { return TReverseIterator(End(Container)); }
template <typename T, size_t N> FORCEINLINE constexpr auto RBegin( T(&& Container)[N]) { return TReverseIterator(End(Container)); }
template <typename T, size_t N> FORCEINLINE constexpr auto RBegin(const T(& Container)[N]) { return TReverseIterator(End(Container)); }
template <typename T, size_t N> FORCEINLINE constexpr auto RBegin(const T(&& Container)[N]) { return TReverseIterator(End(Container)); }
/** Overloads the RBegin algorithm for initializer_list. */
template <typename T>
FORCEINLINE constexpr auto RBegin(initializer_list<T> Container)
{
return TReverseIterator(Container.end());
}
/** @return The reverse iterator to the end of a container. */
template <typename T> requires (requires(T&& Container) { { Container.REnd() } -> CForwardIterator; })
FORCEINLINE constexpr auto REnd(T&& Container)
{
return Container.REnd();
}
/** Overloads the REnd algorithm for arrays. */
template <typename T, size_t N> FORCEINLINE constexpr auto REnd( T(& Container)[N]) { return TReverseIterator(Begin(Container)); }
template <typename T, size_t N> FORCEINLINE constexpr auto REnd( T(&& Container)[N]) { return TReverseIterator(Begin(Container)); }
template <typename T, size_t N> FORCEINLINE constexpr auto REnd(const T(& Container)[N]) { return TReverseIterator(Begin(Container)); }
template <typename T, size_t N> FORCEINLINE constexpr auto REnd(const T(&& Container)[N]) { return TReverseIterator(Begin(Container)); }
/** Overloads the REnd algorithm for initializer_list. */
template <typename T>
FORCEINLINE constexpr auto REnd(initializer_list<T> Container)
{
return TReverseIterator(Container.begin());
}
NAMESPACE_END(Iteration)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -14,6 +14,8 @@ NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_MODULE_BEGIN(Utility)
// ReSharper disable CppInconsistentNaming
// Platform information macro // Platform information macro
#ifndef PLATFORM_NAME #ifndef PLATFORM_NAME
@ -527,6 +529,8 @@ NAMESPACE_PRIVATE_END
#define U32TEXT(X) U32TEXT_PASTE(X) #define U32TEXT(X) U32TEXT_PASTE(X)
#define UNICODETEXT(X) U32TEXT_PASTE(X) #define UNICODETEXT(X) U32TEXT_PASTE(X)
// ReSharper restore CppInconsistentNaming
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ NAMESPACE_PRIVATE_END
#define VARARGS_ACCESS_COPY(ContextName, ContextSource) NAMESPACE_STD::va_list ContextName; va_copy(ContextName, ContextSource) #define VARARGS_ACCESS_COPY(ContextName, ContextSource) NAMESPACE_STD::va_list ContextName; va_copy(ContextName, ContextSource)
/** Accesses the next variadic function argument. */ /** 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. */ /** Ends traversal of the variadic function arguments. */
#define VARARGS_ACCESS_END(ContextName) va_end(ContextName) #define VARARGS_ACCESS_END(ContextName) va_end(ContextName)

View File

@ -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"

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Numeric/Limits.h" #include "Numerics/Limits.h"
#include "Numeric/Literal.h" #include "Numerics/Literals.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
#include <bit> #include <bit>

View File

@ -1,9 +1,9 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Numeric/Bit.h" #include "Numerics/Bit.h"
#include "Numeric/Limits.h" #include "Numerics/Limits.h"
#include "Numeric/Numbers.h" #include "Numerics/Numbers.h"
#include "Templates/Tuple.h" #include "Templates/Tuple.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
@ -444,83 +444,83 @@ RESOLVE_ARITHMETIC_AMBIGUITY_2_ARGS(CArithmetic, IsNearlyZero)
template <CFloatingPoint T> template <CFloatingPoint T>
NODISCARD FORCEINLINE constexpr bool IsInfinity(T A) NODISCARD FORCEINLINE constexpr bool IsInfinity(T A)
{ {
using Traits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>; using FTraits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>;
auto IntegralValue = Math::BitCast<typename Traits::FIntegralT>(A); auto IntegralValue = Math::BitCast<typename FTraits::FIntegralT>(A);
return (IntegralValue & Traits::ExponentMask) == Traits::ExponentMask && (IntegralValue & Traits::MantissaMask) == 0; return (IntegralValue & FTraits::ExponentMask) == FTraits::ExponentMask && (IntegralValue & FTraits::MantissaMask) == 0;
} }
/** @return true if the given value is NaN, false otherwise. */ /** @return true if the given value is NaN, false otherwise. */
template <CFloatingPoint T> template <CFloatingPoint T>
NODISCARD FORCEINLINE constexpr bool IsNaN(T A) NODISCARD FORCEINLINE constexpr bool IsNaN(T A)
{ {
using Traits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>; using FTraits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>;
auto IntegralValue = Math::BitCast<typename Traits::FIntegralT>(A); auto IntegralValue = Math::BitCast<typename FTraits::FIntegralT>(A);
return (IntegralValue & Traits::ExponentMask) == Traits::ExponentMask && (IntegralValue & Traits::MantissaMask) != 0; return (IntegralValue & FTraits::ExponentMask) == FTraits::ExponentMask && (IntegralValue & FTraits::MantissaMask) != 0;
} }
/** @return true if the given value is normal, false otherwise. */ /** @return true if the given value is normal, false otherwise. */
template <CFloatingPoint T> template <CFloatingPoint T>
NODISCARD FORCEINLINE constexpr bool IsNormal(T A) NODISCARD FORCEINLINE constexpr bool IsNormal(T A)
{ {
using Traits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>; using FTraits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>;
auto IntegralValue = Math::BitCast<typename Traits::FIntegralT>(A); auto IntegralValue = Math::BitCast<typename FTraits::FIntegralT>(A);
return (IntegralValue & Traits::ExponentMask) != 0 && (IntegralValue & Traits::ExponentMask) != Traits::ExponentMask; return (IntegralValue & FTraits::ExponentMask) != 0 && (IntegralValue & FTraits::ExponentMask) != FTraits::ExponentMask;
} }
/** @return true if the given value is subnormal, false otherwise. */ /** @return true if the given value is subnormal, false otherwise. */
template <CFloatingPoint T> template <CFloatingPoint T>
NODISCARD FORCEINLINE constexpr bool IsDenorm(T A) NODISCARD FORCEINLINE constexpr bool IsDenorm(T A)
{ {
using Traits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>; using FTraits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>;
auto IntegralValue = Math::BitCast<typename Traits::FIntegralT>(A); auto IntegralValue = Math::BitCast<typename FTraits::FIntegralT>(A);
return (IntegralValue & Traits::ExponentMask) == 0 && (IntegralValue & Traits::MantissaMask) != 0; return (IntegralValue & FTraits::ExponentMask) == 0 && (IntegralValue & FTraits::MantissaMask) != 0;
} }
/** @return true if the given value is negative, even -0.0, false otherwise. */ /** @return true if the given value is negative, even -0.0, false otherwise. */
template <CFloatingPoint T> template <CFloatingPoint T>
NODISCARD FORCEINLINE constexpr bool IsNegative(T A) NODISCARD FORCEINLINE constexpr bool IsNegative(T A)
{ {
using Traits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>; using FTraits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>;
auto IntegralValue = Math::BitCast<typename Traits::FIntegralT>(A); auto IntegralValue = Math::BitCast<typename FTraits::FIntegralT>(A);
return (IntegralValue & Traits::SignMask) >> Traits::SignShift; return (IntegralValue & FTraits::SignMask) >> FTraits::SignShift;
} }
/** @return The exponent of the given value. */ /** @return The exponent of the given value. */
template <CFloatingPoint T> template <CFloatingPoint T>
NODISCARD FORCEINLINE constexpr uint Exponent(T A) NODISCARD FORCEINLINE constexpr uint Exponent(T A)
{ {
using Traits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>; using FTraits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>;
auto IntegralValue = Math::BitCast<typename Traits::FIntegralT>(A); auto IntegralValue = Math::BitCast<typename FTraits::FIntegralT>(A);
return ((IntegralValue & Traits::ExponentMask) >> Traits::ExponentShift) - Traits::ExponentBias; return ((IntegralValue & FTraits::ExponentMask) >> FTraits::ExponentShift) - FTraits::ExponentBias;
} }
/** @return The NaN value with the given payload. */ /** @return The NaN value with the given payload. */
template <CFloatingPoint T, CUnsignedIntegral U> template <CFloatingPoint T, CUnsignedIntegral U>
NODISCARD FORCEINLINE constexpr T NaN(U Payload) NODISCARD FORCEINLINE constexpr T NaN(U Payload)
{ {
using Traits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>; using FTraits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>;
checkf(Payload != 0, TEXT("Illegal payload. It must not be zero.")); checkf(Payload != 0, TEXT("Illegal payload. It must not be zero."));
checkf(Payload < (static_cast<typename Traits::FIntegralT>(1) << Traits::MantissaBits), TEXT("Illegal payload. It must be less than 2^MantissaBits.")); checkf(Payload < (static_cast<typename FTraits::FIntegralT>(1) << FTraits::MantissaBits), TEXT("Illegal payload. It must be less than 2^MantissaBits."));
if (Payload == 0) return TNumericLimits<T>::QuietNaN(); if (Payload == 0) return TNumericLimits<T>::QuietNaN();
typename Traits::FIntegralT ValidPayload = Payload & Traits::MantissaMask; typename FTraits::FIntegralT ValidPayload = Payload & FTraits::MantissaMask;
return Math::BitCast<T>(ValidPayload | Traits::ExponentMask); return Math::BitCast<T>(ValidPayload | FTraits::ExponentMask);
} }
/** @return The NaN value with the given payload. */ /** @return The NaN value with the given payload. */
@ -536,11 +536,11 @@ NODISCARD FORCEINLINE constexpr T NaN(U Payload)
template <CFloatingPoint T> template <CFloatingPoint T>
NODISCARD FORCEINLINE constexpr auto NaNPayload(T A) NODISCARD FORCEINLINE constexpr auto NaNPayload(T A)
{ {
using Traits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>; using FTraits = NAMESPACE_PRIVATE::TFloatingTypeTraits<T>;
auto IntegralValue = Math::BitCast<typename Traits::FIntegralT>(A); auto IntegralValue = Math::BitCast<typename FTraits::FIntegralT>(A);
return IntegralValue & Traits::MantissaMask; return IntegralValue & FTraits::MantissaMask;
} }
/** @return The NaN payload of the given value. */ /** @return The NaN payload of the given value. */

View 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"

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Numeric/Bit.h" #include "Numerics/Bit.h"
#include "Numeric/Math.h" #include "Numerics/Math.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Redcraft)

View File

@ -1,4 +0,0 @@
#pragma once
#include "CoreTypes.h"
#include "Range/Utility.h"

View File

@ -0,0 +1,183 @@
#pragma once
#include "CoreTypes.h"
#include "Ranges/View.h"
#include "Ranges/Pipe.h"
#include "Ranges/Utility.h"
#include "Templates/Utility.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Ranges)
/**
* A view adapter that references other range.
* No matter which it is base range, the reference view always satisfies the same range concept.
*/
template <CRange R> requires (CObject<R>)
class TRefView : public IBasicViewInterface<TRefView<R>>
{
private:
// Use the function to check constructability.
static void Func(R&);
static void Func(R&&) = delete;
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 Ranges::Begin(*Ptr); }
NODISCARD FORCEINLINE constexpr TRangeSentinel<R> End() const { return Ranges::End (*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; }
private:
R* Ptr;
};
template <typename R>
TRefView(R&) -> TRefView<R>;
static_assert( CInputRange<TRefView<IRange< IInputIterator<int&>>>>);
static_assert( CForwardRange<TRefView<IRange< IForwardIterator<int&>>>>);
static_assert(CBidirectionalRange<TRefView<IRange<IBidirectionalIterator<int&>>>>);
static_assert( CRandomAccessRange<TRefView<IRange< IRandomAccessIterator<int&>>>>);
static_assert( CContiguousRange<TRefView<IRange< IContiguousIterator<int&>>>>);
static_assert(CCommonRange<TRefView<ICommonRange< IForwardIterator<int>>>>);
static_assert( CSizedRange<TRefView< ISizedRange<IInputOrOutputIterator<int>>>>);
static_assert( CView<TRefView< IRange<IInputOrOutputIterator<int>>>>);
static_assert(COutputRange<TRefView<IRange<IOutputIterator<int&>>>, int>);
NAMESPACE_END(Ranges)
template <typename T>
constexpr bool bEnableBorrowedRange<Ranges::TRefView<T>> = true;
NAMESPACE_BEGIN(Ranges)
/**
* A view adapter that has unique ownership of a range.
* No matter which it is base range, the reference view always satisfies the same range concept.
* Specify, the base range type must be movable, and the owning view always is movable but not copyable.
*/
template <CRange R> requires (CMovable<R> && !NAMESPACE_PRIVATE::TIsInitializerList<R>::Value)
class TOwningView : public IBasicViewInterface<TOwningView<R>>
{
public:
FORCEINLINE constexpr TOwningView() requires (CDefaultConstructible<R>) = default;
FORCEINLINE constexpr TOwningView(const TOwningView&) = delete;
FORCEINLINE constexpr TOwningView(TOwningView&&) = default;
FORCEINLINE constexpr TOwningView(R&& InRange) : Base(MoveTemp(InRange)) { }
FORCEINLINE constexpr TOwningView& operator=(const TOwningView&) = delete;
FORCEINLINE constexpr TOwningView& operator=(TOwningView&&) = default;
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 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 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) { 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); }
NODISCARD FORCEINLINE constexpr const R& GetBase() const& { return AsConst(Base); }
NODISCARD FORCEINLINE constexpr const R&& GetBase() const&& { return MoveTemp(AsConst(Base)); }
private:
NO_UNIQUE_ADDRESS R Base;
};
static_assert( CInputRange<TOwningView<IRange< IInputIterator<int&>>>>);
static_assert( CForwardRange<TOwningView<IRange< IForwardIterator<int&>>>>);
static_assert(CBidirectionalRange<TOwningView<IRange<IBidirectionalIterator<int&>>>>);
static_assert( CRandomAccessRange<TOwningView<IRange< IRandomAccessIterator<int&>>>>);
static_assert( CContiguousRange<TOwningView<IRange< IContiguousIterator<int&>>>>);
static_assert(CCommonRange<TOwningView<ICommonRange< IForwardIterator<int>>>>);
static_assert( CSizedRange<TOwningView< ISizedRange<IInputOrOutputIterator<int>>>>);
static_assert( CView<TOwningView< IRange<IInputOrOutputIterator<int>>>>);
static_assert(COutputRange<TOwningView<IRange<IOutputIterator<int&>>>, int>);
NAMESPACE_END(Ranges)
template <typename T>
constexpr bool bEnableBorrowedRange<Ranges::TOwningView<T>> = bEnableBorrowedRange<T>;
NAMESPACE_BEGIN(Ranges)
/** Creates A view adapter that includes all elements of a range. */
template <CViewableRange R>
NODISCARD FORCEINLINE constexpr auto All(R&& InRange)
{
if constexpr (CView<TDecay<R>>)
{
return TDecay<R>(Forward<R>(InRange));
}
else if constexpr (requires { TRefView(Forward<R>(InRange)); })
{
return TRefView(Forward<R>(InRange));
}
else return TOwningView(Forward<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 { Ranges::All(DeclVal<R>()); }) (R&& Base)
{
return Ranges::All(Forward<R>(Base));
});
return TAdaptorClosure<FClosure>();
}
/** A view adapter that includes all elements of a range. */
template <CViewableRange R>
using TAllView = decltype(Ranges::All(DeclVal<R>()));
static_assert( CInputRange<TAllView<IRange< IInputIterator<int&>>>>);
static_assert( CForwardRange<TAllView<IRange< IForwardIterator<int&>>>>);
static_assert(CBidirectionalRange<TAllView<IRange<IBidirectionalIterator<int&>>>>);
static_assert( CRandomAccessRange<TAllView<IRange< IRandomAccessIterator<int&>>>>);
static_assert( CContiguousRange<TAllView<IRange< IContiguousIterator<int&>>>>);
static_assert(CCommonRange<TAllView<ICommonRange< IForwardIterator<int>>>>);
static_assert( CSizedRange<TAllView< ISizedRange<IInputOrOutputIterator<int>>>>);
static_assert( CView<TAllView< IRange<IInputOrOutputIterator<int>>>>);
static_assert(COutputRange<TAllView<IRange<IOutputIterator<int&>>>, int>);
NAMESPACE_END(Ranges)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -0,0 +1,170 @@
#pragma once
#include "CoreTypes.h"
#include "Ranges/View.h"
#include "Ranges/Utility.h"
#include "Ranges/AllView.h"
#include "Templates/Utility.h"
#include "Ranges/TransformView.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
// NOTE: In the STL, use std::from_range_t as a disambiguation tag that resolves ambiguity
// introduced by the list-initialization. For example, for the following code:
//
// R RangeOfInts = /* ... */;
// static_assert(CRange<R> and CSameAs<TRangeElement<R>, int>);
//
// TArray Arr(RangeOfInts);
// TArray Brr{RangeOfInts};
//
// If R is TArray<int> than decltype(Arr) is TArray<int> and decltype(Brr) is TArray<int>,
// otherwise, decltype(Arr) is TArray<int> and decltype(Brr) is TArray<R>.
//
// But Redcraft can't use the std::from_range_t tag because list-initialization is discouraged.
/** A concept specifies a container that can reserve size. */
template <typename C>
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 T>
concept CAppendableContainer =
requires (C& Container, T&& Object)
{
requires
(
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(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>)
NODISCARD FORCEINLINE constexpr auto To(R&& Range, Ts&&... Args)
{
if constexpr (!CInputRange<C> || CConvertibleTo<TRangeReference<R>, TRangeElement<C>>)
{
if constexpr (CConstructibleFrom<C, R, Ts...>)
{
return C(Forward<R>(Range), Forward<Ts>(Args)...);
}
else if constexpr (CCommonRange<R> && CInputRange<R> && CConstructibleFrom<C, TRangeIterator<R>, TRangeSentinel<R>, Ts...>)
{
return C(Ranges::Begin(Range), Ranges::End(Range), Forward<Ts>(Args)...);
}
else if constexpr (CConstructibleFrom<C, Ts...> && CAppendableContainer<C, TRangeReference<R>>)
{
C Result(Forward<Ts>(Args)...);
if constexpr (CSizedRange<R> && CReservableContainer<C>)
{
Result.Reserve(Ranges::Num(Range));
}
for (TRangeReference<R> Element : Range)
{
Ranges::AppendTo(Result, Forward<TRangeReference<R>>(Element));
}
return Result;
}
else static_assert(sizeof(R) == -1, "The container type is not constructible from a range");
}
else
{
if constexpr (CInputRange<TRangeReference<C>>)
{
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");
}
}
/** Constructs a non-view object from the elements of the range. */
template <template <typename...> typename C, CInputRange R, typename... Ts>
NODISCARD FORCEINLINE constexpr auto To(R&& Range, Ts&&... Args)
{
if constexpr (requires { C(DeclVal<R>(), DeclVal<Ts>()...); })
{
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 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");
}
/** Constructs a non-view object from the elements of the range. */
template <typename C, typename... Ts> requires (!CView<C>)
NODISCARD FORCEINLINE constexpr auto To(Ts&&... Args)
{
using FClosure = decltype([]<CInputRange R, typename... Us> requires (requires { Ranges::To<C>(DeclVal<R>(), DeclVal<Us>()...); }) (R&& Range, Us&&... Args)
{
return Ranges::To<C>(Forward<R>(Range), Forward<Us>(Args)...);
});
return TAdaptorClosure<FClosure, TDecay<Ts>...>(Forward<Ts>(Args)...);
}
/** Constructs a non-view object from the elements of the range. */
template <template <typename...> typename C, typename... Ts>
NODISCARD FORCEINLINE constexpr auto To(Ts&&... Args)
{
using FClosure = decltype([]<CInputRange R, typename... Us> requires (requires { Ranges::To<C>(DeclVal<R>(), DeclVal<Us>()...); }) (R&& Range, Us&&... Args)
{
return Ranges::To<C>(Forward<R>(Range), Forward<Us>(Args)...);
});
return TAdaptorClosure<FClosure, TDecay<Ts>...>(Forward<Ts>(Args)...);
}
NAMESPACE_END(Ranges)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -0,0 +1,357 @@
#pragma once
#include "CoreTypes.h"
#include "Ranges/View.h"
#include "Ranges/Utility.h"
#include "Memory/Address.h"
#include "Templates/Utility.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Ranges)
/** A view type that produces a view of no elements of a particular type. */
template <CObject T>
class TEmptyView : public IBasicViewInterface<TEmptyView<T>>
{
public:
using FElementType = T;
using FReference = T&;
using FIterator = T*;
using FSentinel = T*;
FORCEINLINE constexpr TEmptyView() = default;
NODISCARD static FORCEINLINE constexpr FIterator Begin() { return nullptr; }
NODISCARD static FORCEINLINE constexpr FSentinel End() { return nullptr; }
NODISCARD static FORCEINLINE constexpr T* GetData() { return nullptr; }
NODISCARD static FORCEINLINE constexpr size_t Num() { return 0; }
NODISCARD static FORCEINLINE constexpr bool IsEmpty() { return true; }
};
static_assert(CContiguousRange<TEmptyView<int>>);
static_assert( CCommonRange<TEmptyView<int>>);
static_assert( CSizedRange<TEmptyView<int>>);
static_assert( CView<TEmptyView<int>>);
NAMESPACE_END(Ranges)
template <typename T>
constexpr bool bEnableBorrowedRange<Ranges::TEmptyView<T>> = true;
NAMESPACE_BEGIN(Ranges)
/** A view type that contains exactly one element of a specified value. */
template <CObject T> requires (CMoveConstructible<T>)
class TSingleView : public IBasicViewInterface<TSingleView<T>>
{
public:
using FElementType = T;
using FReference = T&;
using FConstReference = const T&;
using FIterator = T*;
using FConstIterator = const T*;
using FSentinel = T*;
using FConstSentinel = const T*;
FORCEINLINE constexpr TSingleView() requires (CDefaultConstructible<T>) = default;
FORCEINLINE constexpr explicit TSingleView(const T& InValue) requires (CCopyConstructible<T>) : Value(InValue) { }
FORCEINLINE constexpr explicit TSingleView(T&& InValue) : Value(MoveTemp(InValue)) { }
template <typename... Ts> requires (CConstructibleFrom<T, Ts...>)
FORCEINLINE constexpr explicit TSingleView(FInPlace, Ts&&... Args) : Value(Forward<Ts>(Args)...) { }
FORCEINLINE constexpr FIterator Begin() { return GetData(); }
FORCEINLINE constexpr FConstIterator Begin() const { return GetData(); }
FORCEINLINE constexpr FSentinel End() { return GetData() + 1; }
FORCEINLINE constexpr FConstSentinel End() const { return GetData() + 1; }
NODISCARD FORCEINLINE constexpr T* GetData() { return AddressOf(Value); }
NODISCARD FORCEINLINE constexpr const T* GetData() const { return AddressOf(Value); }
NODISCARD static FORCEINLINE constexpr size_t Num() { return 1; }
NODISCARD static FORCEINLINE constexpr bool IsEmpty() { return false; }
private:
NO_UNIQUE_ADDRESS T Value;
};
template <typename T>
TSingleView(T) -> TSingleView<T>;
static_assert(CContiguousRange<TSingleView<int>>);
static_assert( CCommonRange<TSingleView<int>>);
static_assert( CSizedRange<TSingleView<int>>);
static_assert( CView<TSingleView<int>>);
/** A view type that generates a sequence of elements by repeatedly incrementing an initial value. Can be either bounded or unbounded. */
template <CWeaklyIncrementable W, CWeaklyEqualityComparable<W> S = FUnreachableSentinel> requires (CSemiregular<S> && CCopyable<W>)
class TIotaView : public IBasicViewInterface<TIotaView<W, S>>
{
private:
class FIteratorImpl;
class FSentinelImpl;
public:
using FElementType = TRemoveCV<W>;
using FReference = W;
using FIterator = FIteratorImpl;
using FSentinel = TConditional<CSameAs<W, S>, FIteratorImpl, FSentinelImpl>;
FORCEINLINE constexpr TIotaView() requires (CDefaultConstructible<W>) = default;
FORCEINLINE constexpr explicit TIotaView(W InValue) requires (CDefaultConstructible<S>) : First(InValue), Last() { }
FORCEINLINE constexpr explicit TIotaView(TIdentity<W> InValue, TIdentity<S> InLast) : First(InValue), Last(InLast) { }
FORCEINLINE constexpr explicit TIotaView(FIterator InFirst, FSentinel InLast) : First(InFirst.Value), Last(InLast.Value) { }
FORCEINLINE constexpr explicit TIotaView(FIterator InFirst, FUnreachableSentinel) requires (CSameAs<S, FUnreachableSentinel>) : First(InFirst.Value) { }
NODISCARD FORCEINLINE constexpr FIterator Begin() const { return FIterator(First); }
NODISCARD FORCEINLINE constexpr FSentinel End() const { return FSentinel(Last); }
NODISCARD FORCEINLINE constexpr size_t Num() const requires ((CIntegral<W> && CIntegral<S>) || CSizedSentinelFor<S, W>) { return Last - First; }
NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return First == Last; }
private:
NO_UNIQUE_ADDRESS W First;
NO_UNIQUE_ADDRESS S Last;
class FIteratorImpl final
{
public:
using FElementType = TRemoveCV<W>;
FORCEINLINE constexpr FIteratorImpl() requires (CDefaultConstructible<W>) = default;
NODISCARD friend FORCEINLINE constexpr bool operator==(const FIteratorImpl& LHS, const FIteratorImpl& RHS) requires (CEqualityComparable<W>) { return LHS.Value == RHS.Value; }
NODISCARD FORCEINLINE constexpr FReference operator*() const { return Value; }
NODISCARD FORCEINLINE constexpr const W* operator->() const { return AddressOf(Value); }
FORCEINLINE constexpr FIteratorImpl& operator++() { ++Value; return *this; }
FORCEINLINE constexpr FIteratorImpl operator++(int) { FIteratorImpl Temp = *this; ++*this; return Temp; }
private:
NO_UNIQUE_ADDRESS W Value;
constexpr explicit FIteratorImpl(W InValue) : Value(InValue) { }
friend FSentinelImpl;
friend TIotaView;
};
class FSentinelImpl final
{
public:
FORCEINLINE constexpr FSentinelImpl() = default;
NODISCARD FORCEINLINE constexpr bool operator==(const FIteratorImpl& InValue) const& { return Value == InValue.Value; }
private:
NO_UNIQUE_ADDRESS S Value;
FORCEINLINE constexpr FSentinelImpl(S InValue) : Value(InValue) { }
friend TIotaView;
};
};
template <typename T, typename U>
TIotaView(T, U) -> TIotaView<T, U>;
static_assert(CForwardRange<TIotaView<int>>);
static_assert( CView<TIotaView<int>>);
NAMESPACE_END(Ranges)
template <typename T, typename U>
constexpr bool bEnableBorrowedRange<Ranges::TIotaView<T, U>> = true;
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>>)
class TRepeatView : public IBasicViewInterface<TRepeatView<W, bIsUnreachable>>
{
private:
class FIteratorImpl;
public:
using FElementType = W;
using FReference = const W&;
using FIterator = FIteratorImpl;
using FSentinel = TConditional<bIsUnreachable, FUnreachableSentinel, FIterator>;
FORCEINLINE constexpr TRepeatView() requires (CDefaultConstructible<W>) = default;
FORCEINLINE constexpr explicit TRepeatView(const W& InValue) requires (bIsUnreachable && CCopyConstructible<W>) : Value(InValue) { }
FORCEINLINE constexpr explicit TRepeatView(W&& InValue) requires (bIsUnreachable) : Value(MoveTemp(InValue)) { }
FORCEINLINE constexpr explicit TRepeatView(const W& InValue, size_t InCount) requires (!bIsUnreachable && CCopyConstructible<W>) : Value(MoveTemp(InValue)), Count(InCount) { }
FORCEINLINE constexpr explicit TRepeatView(W&& InValue, size_t InCount) requires (!bIsUnreachable) : Value(MoveTemp(InValue)), Count(InCount) { }
template <typename... Ts> requires (CConstructibleFrom<W, Ts...>)
FORCEINLINE constexpr explicit TRepeatView(FInPlace, Ts&&... Args, size_t InCount) : Value(Forward<Ts>(Args)...), Count(InCount) { }
NODISCARD FORCEINLINE constexpr FIterator Begin() const { return FIterator(Value, 0); }
NODISCARD FORCEINLINE constexpr FSentinel End() const
{
if constexpr (bIsUnreachable)
{
return UnreachableSentinel;
}
else return FSentinel(Value, Count);
}
NODISCARD FORCEINLINE constexpr size_t Num() const requires (!bIsUnreachable) { return Count; }
private:
using FSizeType = TConditional<bIsUnreachable, FUnreachableSentinel, size_t>;
NO_UNIQUE_ADDRESS W Value;
NO_UNIQUE_ADDRESS FSizeType Count;
class FIteratorImpl final
{
public:
using FElementType = W;
FORCEINLINE constexpr FIteratorImpl() requires (CDefaultConstructible<W>) = default;
NODISCARD friend FORCEINLINE constexpr bool operator==(const FIteratorImpl& LHS, const FIteratorImpl& RHS) { return LHS.Current == RHS.Current; }
NODISCARD friend FORCEINLINE constexpr strong_ordering operator<=>(const FIteratorImpl& LHS, const FIteratorImpl& RHS) { return LHS.Current <=> RHS.Current; }
NODISCARD FORCEINLINE constexpr FReference operator*() const { return *Ptr; }
NODISCARD FORCEINLINE constexpr const W* operator->() const { return Ptr; }
NODISCARD FORCEINLINE constexpr FReference operator[](ptrdiff) const { return *Ptr; }
FORCEINLINE constexpr FIteratorImpl& operator++() { ++Current; return *this; }
FORCEINLINE constexpr FIteratorImpl& operator--() { --Current; return *this; }
FORCEINLINE constexpr FIteratorImpl operator++(int) { FIteratorImpl Temp = *this; ++*this; return Temp; }
FORCEINLINE constexpr FIteratorImpl operator--(int) { FIteratorImpl Temp = *this; --*this; return Temp; }
FORCEINLINE constexpr FIteratorImpl& operator+=(ptrdiff Offset) { Current += Offset; return *this; }
FORCEINLINE constexpr FIteratorImpl& operator-=(ptrdiff Offset) { Current -= Offset; return *this; }
NODISCARD friend FORCEINLINE constexpr FIteratorImpl operator+(FIteratorImpl Iter, ptrdiff Offset) { FIteratorImpl Temp = Iter; Temp += Offset; return Temp; }
NODISCARD friend FORCEINLINE constexpr FIteratorImpl operator+(ptrdiff Offset, FIteratorImpl Iter) { FIteratorImpl Temp = Iter; Temp += Offset; return Temp; }
NODISCARD FORCEINLINE constexpr FIteratorImpl operator-(ptrdiff Offset) const { FIteratorImpl Temp = *this; Temp -= Offset; return Temp; }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FIteratorImpl& LHS, const FIteratorImpl& RHS) { return LHS.Current - RHS.Current; }
private:
const W* Ptr;
NO_UNIQUE_ADDRESS size_t Current;
FORCEINLINE constexpr FIteratorImpl(const W& InObject, size_t InCurrent) : Ptr(AddressOf(InObject)), Current(InCurrent) { }
friend TRepeatView;
};
};
template <typename W>
TRepeatView(W) -> TRepeatView<W>;
template <typename W>
TRepeatView(W, size_t) -> TRepeatView<W, false>;
static_assert(CRandomAccessRange<TRepeatView<int, false>>);
static_assert( CCommonRange<TRepeatView<int, false>>);
static_assert( CSizedRange<TRepeatView<int, false>>);
static_assert( CView<TRepeatView<int, false>>);
NAMESPACE_END(Ranges)
NAMESPACE_BEGIN(Ranges)
/** A view of no elements of a particular type. */
template <CObject T>
inline constexpr TEmptyView<T> Empty;
/** Creates a view that contains exactly one element of a specified value. */
template <typename T> requires (CObject<TDecay<T>> && CMoveConstructible<TDecay<T>>)
NODISCARD FORCEINLINE constexpr TSingleView<TDecay<T>> Single(T&& Value)
{
return TSingleView<TDecay<T>>(Forward<T>(Value));
}
/** Creates a view that generates a sequence of elements by repeatedly incrementing an initial value. */
template <typename W> requires (CWeaklyIncrementable<TDecay<W>> && CCopyable<TDecay<W>>)
NODISCARD FORCEINLINE constexpr TIotaView<TDecay<W>> Iota(W&& Value)
{
return TIotaView<TDecay<W>>(Forward<W>(Value));
}
/** Creates a view that generates a sequence of elements by repeatedly incrementing an initial value. */
template <typename W, typename S> requires (CWeaklyIncrementable<TDecay<W>> && CWeaklyEqualityComparable<W, S> && CCopyable<TDecay<W>> && CSemiregular<TDecay<S>>)
NODISCARD FORCEINLINE constexpr TIotaView<TDecay<W>, TDecay<S>> Iota(W&& Value, S&& Last)
{
return TIotaView<TDecay<W>, TDecay<S>>(Forward<W>(Value), Forward<S>(Last));
}
/** Creates a view that generates a sequence of elements by repeatedly producing the same value. */
template <typename W> requires (CObject<TDecay<W>> && CMoveConstructible<TDecay<W>>)
NODISCARD FORCEINLINE constexpr TRepeatView<TDecay<W>> Repeat(W&& Value)
{
return TRepeatView<TDecay<W>>(Forward<W>(Value));
}
/** Creates a view that generates a sequence of elements by repeatedly producing the same value. */
template <typename W> requires (CObject<TDecay<W>> && CMoveConstructible<TDecay<W>>)
NODISCARD FORCEINLINE constexpr TRepeatView<TDecay<W>, false> Repeat(W&& Value, size_t Count)
{
return TRepeatView<TDecay<W>, false>(Forward<W>(Value), Count);
}
NAMESPACE_END(Ranges)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -0,0 +1,191 @@
#pragma once
#include "CoreTypes.h"
#include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.h"
#include "Templates/Invoke.h"
#include "Iterators/Utility.h"
#include "Iterators/BasicIterator.h"
#include "Memory/Address.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 consists of the elements of a range that satisfies a predicate.
* When based on an input view, the filter view satisfies at least an input view up to a bidirectional view.
* When based on a common view, the filter view satisfies a common view.
*/
template <CInputRange V, CPredicate<TRangeReference<V>> Pred> requires (CView<V> && CObject<Pred> && CMoveConstructible<Pred>)
class TFilterView : public IBasicViewInterface<TFilterView<V, Pred>>
{
private:
class FIteratorImpl;
class FSentinelImpl;
public:
using FElementType = TRangeElement<V>;
using FReference = TRangeReference<V>;
using FIterator = FIteratorImpl;
using FSentinel = TConditional<CCommonRange<V>, FIteratorImpl, FSentinelImpl>;
FORCEINLINE constexpr TFilterView() requires (CDefaultConstructible<V> && CDefaultConstructible<Pred>) = default;
FORCEINLINE constexpr explicit TFilterView(V InBase, Pred InPredicate) : Base(MoveTemp(InBase)), Predicate(MoveTemp(InPredicate)) { }
NODISCARD FORCEINLINE constexpr FIterator Begin()
{
FIterator Iter(*this, Ranges::Begin(Base));
do
{
if (Iter == End()) break;
if (InvokeResult<bool>(GetPredicate(), *Iter)) break;
++Iter;
}
while (false);
if constexpr (!CForwardRange<V>) return MoveTemp(Iter);
return Iter;
}
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); }
NODISCARD FORCEINLINE constexpr const Pred& GetPredicate() const { return Predicate; }
private:
NO_UNIQUE_ADDRESS V Base;
NO_UNIQUE_ADDRESS Pred Predicate;
class FIteratorImpl final
{
public:
using FElementType = TIteratorElement<TRangeIterator<V>>;
FORCEINLINE constexpr FIteratorImpl() requires (CDefaultConstructible<TRangeIterator<V>>) { } // Use '{ }' instead of '= default;' to avoid MSVC bug.
NODISCARD friend FORCEINLINE constexpr bool operator==(const FIteratorImpl& LHS, const FIteratorImpl& RHS)
{
return LHS.GetBase() == RHS.GetBase();
}
NODISCARD FORCEINLINE constexpr TRangeReference<V> operator*() const { return *GetBase(); }
NODISCARD FORCEINLINE constexpr auto operator->() const requires (requires(const TRangeIterator<V> Iter) { { ToAddress(Iter) } -> CSameAs<TIteratorPointer<TRangeIterator<V>>>; }) { return ToAddress(GetBase()); }
FORCEINLINE constexpr FIteratorImpl& operator++()
{
do ++Current; while (*this != Owner->End() && !InvokeResult<bool>(Owner->GetPredicate(), *Current));
return *this;
}
FORCEINLINE constexpr FIteratorImpl& operator--() requires (CBidirectionalIterator<TRangeIterator<V>>)
{
do --Current; while (!InvokeResult<bool>(Owner->GetPredicate(), *Current));
return *this;
}
FORCEINLINE constexpr void operator++(int) { ++*this; }
FORCEINLINE constexpr FIteratorImpl operator++(int) requires (CForwardIterator<TRangeIterator<V>>) { FIteratorImpl Temp = *this; ++*this; return Temp; }
FORCEINLINE constexpr FIteratorImpl operator--(int) requires (CBidirectionalIterator<TRangeIterator<V>>) { FIteratorImpl Temp = *this; --*this; return Temp; }
NODISCARD FORCEINLINE constexpr const TRangeIterator<V>& GetBase() const& { return Current; }
NODISCARD FORCEINLINE constexpr TRangeIterator<V> GetBase() && { return MoveTemp(Current); }
private:
TFilterView* Owner;
NO_UNIQUE_ADDRESS TRangeIterator<V> Current;
FORCEINLINE constexpr FIteratorImpl(TFilterView& InOwner, TRangeIterator<V> InCurrent) : Owner(&InOwner), Current(MoveTemp(InCurrent)) { }
friend FSentinelImpl;
friend TFilterView;
};
class FSentinelImpl final
{
public:
FORCEINLINE constexpr FSentinelImpl() = default;
NODISCARD FORCEINLINE constexpr bool operator==(const FIteratorImpl& InValue) const& { return Current == InValue.Current; }
NODISCARD FORCEINLINE constexpr TRangeSentinel<V> GetBase() const { return Current; }
private:
TRangeSentinel<V> Current;
FORCEINLINE constexpr FSentinelImpl(TFilterView& InOwner, TRangeSentinel<V> InCurrent) : Current(InCurrent) { }
friend TFilterView;
};
};
template <typename R, typename Pred>
TFilterView(R&&, Pred) -> TFilterView<TAllView<R>, Pred>;
static_assert( CInputRange<TFilterView<TAllView<IRange< IInputIterator<int&>>>, bool(*)(int)>>);
static_assert( CForwardRange<TFilterView<TAllView<IRange< IForwardIterator<int&>>>, bool(*)(int)>>);
static_assert(CBidirectionalRange<TFilterView<TAllView<IRange<IBidirectionalIterator<int&>>>, bool(*)(int)>>);
static_assert(CBidirectionalRange<TFilterView<TAllView<IRange< IRandomAccessIterator<int&>>>, bool(*)(int)>>);
static_assert(CBidirectionalRange<TFilterView<TAllView<IRange< IContiguousIterator<int&>>>, bool(*)(int)>>);
static_assert(CCommonRange<TFilterView<TAllView<ICommonRange<IForwardIterator<int>>>, bool(*)(int)>>);
static_assert( CView<TFilterView<TAllView< IRange< IInputIterator<int>>>, bool(*)(int)>>);
NAMESPACE_END(Ranges)
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>()); })
NODISCARD FORCEINLINE constexpr auto Filter(R&& Base, Pred&& Predicate)
{
return TFilterView(Forward<R>(Base), Forward<Pred>(Predicate));
}
/** Creates A view adapter that consists of the elements of a range that satisfies a predicate. */
template <typename Pred>
NODISCARD FORCEINLINE constexpr auto Filter(Pred&& Predicate)
{
using FClosure = decltype([]<CViewableRange R, typename T> requires (requires { Ranges::Filter(DeclVal<R>(), DeclVal<T>()); }) (R&& Base, T&& Predicate)
{
return Ranges::Filter(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

View File

@ -0,0 +1,118 @@
#pragma once
#include "CoreTypes.h"
#include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.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(Ranges)
/**
* A view adapter which dereferences to a rvalue reference.
* When based on an input view, the move view satisfies at least an input view up to a random access view.
* When based on a common view, the move view satisfies a common view.
*/
template <CInputRange V> requires (CView<V>)
class TMoveView : public IBasicViewInterface<TMoveView<V>>
{
public:
using FElementType = TRangeElement<V>;
using FReference = TRangeRValueReference<V>;
FORCEINLINE constexpr TMoveView() requires (CDefaultConstructible<V>) = default;
FORCEINLINE constexpr explicit TMoveView(V InBase) : Base(MoveTemp(InBase)) { }
NODISCARD FORCEINLINE constexpr auto Begin() requires (!CSimpleView<V>)
{
return MakeMoveIterator(Ranges::Begin(Base));
}
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(Ranges::End(Base));
}
else return MakeMoveSentinel(Ranges::End(Base));
}
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V>)
{
if constexpr (CCommonRange<V>)
{
return MakeMoveIterator(Ranges::End(Base));
}
else return MakeMoveSentinel(Ranges::End(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); }
private:
NO_UNIQUE_ADDRESS V Base;
};
template <typename R>
TMoveView(R&&) -> TMoveView<TAllView<R>>;
static_assert( CInputRange<TMoveView<TAllView<IRange< IInputIterator<int&>>>>>);
static_assert( CForwardRange<TMoveView<TAllView<IRange< IForwardIterator<int&>>>>>);
static_assert(CBidirectionalRange<TMoveView<TAllView<IRange<IBidirectionalIterator<int&>>>>>);
static_assert( CRandomAccessRange<TMoveView<TAllView<IRange< IRandomAccessIterator<int&>>>>>);
static_assert( CRandomAccessRange<TMoveView<TAllView<IRange< IContiguousIterator<int&>>>>>);
static_assert(CCommonRange<TMoveView<TAllView<ICommonRange<IForwardIterator<int>>>>>);
static_assert( CView<TMoveView<TAllView< IRange< IInputIterator<int>>>>>);
NAMESPACE_END(Ranges)
template <typename T>
constexpr bool bEnableBorrowedRange<Ranges::TMoveView<T>> = bEnableBorrowedRange<T>;
NAMESPACE_BEGIN(Ranges)
/** Creates A view adapter that dereferences to a rvalue reference. */
template <CViewableRange R> requires (requires { TMoveView(DeclVal<R>()); })
NODISCARD FORCEINLINE constexpr auto Move(R&& Base)
{
return TMoveView(Forward<R>(Base));
}
/** Creates A view adapter that dereferences to a rvalue reference. */
NODISCARD FORCEINLINE constexpr auto Move()
{
using FClosure = decltype([]<CViewableRange R> requires (requires { Ranges::Move(DeclVal<R>()); }) (R&& Base)
{
return Ranges::Move(Forward<R>(Base));
});
return TAdaptorClosure<FClosure>();
}
NAMESPACE_END(Ranges)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -0,0 +1,146 @@
#pragma once
#include "CoreTypes.h"
#include "Ranges/Utility.h"
#include "Templates/Tuple.h"
#include "Templates/Invoke.h"
#include "Templates/Utility.h"
#include "TypeTraits/TypeTraits.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Ranges)
/**
* An interface class template for defining a range adaptor closure.
* When the derived class has a unary operator() with range as a reference and is not itself a range,
* the derived class is the range adaptor closure type and its objects can participate in pipe operations.
* Specify, the unary operator() with any reference qualifier or cv-qualifier must be defined and has same effect.
* Not directly instantiable.
*/
template <CObject D> requires (CSameAs<D, TRemoveCV<D>>)
class IAdaptorClosure { };
/** An adaptor closure helper that wraps a callable object. */
template <CDefaultConstructible F, CMoveConstructible... Ts> requires (CEmpty<F> && ... && CSameAs<TDecay<Ts>, Ts>)
class TAdaptorClosure : public IAdaptorClosure<TAdaptorClosure<F, Ts...>>
{
public:
template <typename... Us> requires (CConstructibleFrom<TTuple<Ts...>, Us...> && ... && CSameAs<TDecay<Us>, Ts>)
FORCEINLINE constexpr explicit TAdaptorClosure(Us&&... InArgs) : Args(Forward<Us>(InArgs)...) { }
template <typename R> requires (CInvocable<F, R, Ts&...>)
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) &
{
return [this, &Range]<size_t... Indices>(TIndexSequence<Indices...>)
{
return Invoke(F(), Forward<R>(Range), Args.template GetValue<Indices>()...);
}
(TMakeIndexSequence<sizeof...(Ts)>());
}
template <typename R> requires (CInvocable<F, R, const Ts&...>)
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) const&
{
return [this, &Range]<size_t... Indices>(TIndexSequence<Indices...>)
{
return Invoke(F(), Forward<R>(Range), Args.template GetValue<Indices>()...);
}
(TMakeIndexSequence<sizeof...(Ts)>());
}
template <typename R> requires (CInvocable<F, R, Ts&&...>)
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) &&
{
return [this, &Range]<size_t... Indices>(TIndexSequence<Indices...>)
{
return Invoke(F(), Forward<R>(Range), MoveTemp(Args).template GetValue<Indices>()...);
}
(TMakeIndexSequence<sizeof...(Ts)>());
}
template <typename R> requires (CInvocable<F, R, const Ts&&...>)
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) const&&
{
return [this, &Range]<size_t... Indices>(TIndexSequence<Indices...>)
{
return Invoke(F(), Forward<R>(Range), MoveTemp(Args).template GetValue<Indices>()...);
}
(TMakeIndexSequence<sizeof...(Ts)>());
}
private:
NO_UNIQUE_ADDRESS TTuple<Ts...> Args;
};
/** A pipe closure that wraps two adaptor closures. */
template <CMoveConstructible T, CMoveConstructible U>
requires (CSameAs<TRemoveCVRef<T>, T> && CDerivedFrom<T, IAdaptorClosure<T>>
&& CSameAs<TRemoveCVRef<U>, U> && CDerivedFrom<U, IAdaptorClosure<U>>)
class TPipeClosure final : public IAdaptorClosure<TPipeClosure<T, U>>
{
public:
template <typename V, typename W>
requires (CSameAs<TRemoveCVRef<V>, T> && CConstructibleFrom<T, V>
&& CSameAs<TRemoveCVRef<W>, U> && CConstructibleFrom<U, W>)
FORCEINLINE constexpr explicit TPipeClosure(V InLHS, W InRHS)
: LHS(Forward<V>(InLHS)), RHS(Forward<W>(InRHS))
{ }
template <typename R> requires (CInvocable<T&, R> && CInvocable<U&, TInvokeResult<T&, R>>)
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) &
{
return Forward<R>(Range) | LHS | RHS;
}
template <typename R> requires (CInvocable<const T&, R> && CInvocable<const U&, TInvokeResult<const T&, R>>)
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) const&
{
return Forward<R>(Range) | LHS | RHS;
}
template <typename R> requires (CInvocable<T&&, R> && CInvocable<U&&, TInvokeResult<T&&, R>>)
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) &&
{
return Forward<R>(Range) | MoveTemp(LHS) | MoveTemp(RHS);
}
template <typename R> requires (CInvocable<const T&&, R> && CInvocable<const U&&, TInvokeResult<const T&&, R>>)
NODISCARD FORCEINLINE constexpr auto operator()(R&& Range) const&&
{
return Forward<R>(Range) | MoveTemp(LHS) | MoveTemp(RHS);
}
private:
NO_UNIQUE_ADDRESS T LHS;
NO_UNIQUE_ADDRESS U RHS;
};
/** Apply the range adaptor closure to the range. */
template <CRange R, CInvocable<R> T> requires (CDerivedFrom<TRemoveCVRef<T>, IAdaptorClosure<TRemoveCVRef<T>>>)
NODISCARD FORCEINLINE constexpr auto operator|(R&& Range, T&& Closure)
{
return Invoke(Forward<T>(Closure), Forward<R>(Range));
}
/** Create a pipe closure that wraps two adaptor closures. */
template <CMoveConstructible T, CMoveConstructible U>
requires (CDerivedFrom<TRemoveCVRef<T>, IAdaptorClosure<TRemoveCVRef<T>>>
&& CDerivedFrom<TRemoveCVRef<U>, IAdaptorClosure<TRemoveCVRef<U>>>)
NODISCARD FORCEINLINE constexpr auto operator|(T&& LHS, U&& RHS)
{
return TPipeClosure<TRemoveCVRef<T>, TRemoveCVRef<U>>(Forward<T>(LHS), Forward<U>(RHS));
}
NAMESPACE_END(Ranges)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View 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"

View File

@ -0,0 +1,186 @@
#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 a specified number of elements from the beginning of a range.
* When based on any view, the take view satisfies the corresponding any view.
* When based on a random access and sized view, the take view satisfies a common view.
*/
template <CView V>
class TTakeView : public IBasicViewInterface<TTakeView<V>>
{
private:
template <bool bConst> class FSentinelImpl;
public:
FORCEINLINE constexpr TTakeView() requires (CDefaultConstructible<V>) = default;
FORCEINLINE constexpr TTakeView(V InBase, size_t InCount) : Base(MoveTemp(InBase)), Count(InCount) { }
NODISCARD FORCEINLINE constexpr auto Begin() requires (!CSimpleView<V>)
{
if constexpr (CSizedRange<V>)
{
if constexpr (CRandomAccessRange<V>)
{
return Ranges::Begin(Base);
}
else return MakeCountedIterator(Ranges::Begin(Base), Num());
}
else return MakeCountedIterator(Ranges::Begin(Base), Count);
}
NODISCARD FORCEINLINE constexpr auto Begin() const requires (CRange<const V>)
{
if constexpr (CSizedRange<const V>)
{
if constexpr (CRandomAccessRange<const V>)
{
return Ranges::Begin(Base);
}
else return MakeCountedIterator(Ranges::Begin(Base), Num());
}
else return MakeCountedIterator(Ranges::Begin(Base), Count);
}
NODISCARD FORCEINLINE constexpr auto End() requires (!CSimpleView<V>)
{
if constexpr (CSizedRange<V>)
{
if constexpr (CRandomAccessRange<V>)
{
return Ranges::Begin(Base) + Num();
}
else return DefaultSentinel;
}
else return FSentinelImpl<false>(Ranges::End(Base));
}
NODISCARD FORCEINLINE constexpr auto End() const requires (CRange<const V>)
{
if constexpr (CSizedRange<const V>)
{
if constexpr (CRandomAccessRange<const V>)
{
return Ranges::Begin(Base) + Num();
}
else return DefaultSentinel;
}
else return FSentinelImpl<true>(Ranges::End(Base));
}
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); }
private:
NO_UNIQUE_ADDRESS V Base;
size_t Count;
template <bool bConst>
class FSentinelImpl final
{
private:
using FBase = TConditional<bConst, const V, V>;
public:
FORCEINLINE constexpr FSentinelImpl() = default;
FORCEINLINE constexpr FSentinelImpl(FSentinelImpl<!bConst> Sentinel) requires (bConst && CConvertibleTo<TRangeSentinel<V>, TRangeSentinel<FBase>>)
: Current(Sentinel.Current)
{ }
NODISCARD FORCEINLINE constexpr bool operator==(const TCountedIterator<TRangeIterator<FBase>>& InValue) const&
{
return InValue.Num() == 0 || InValue.GetBase() == Current;
}
template <bool bOther = !bConst> requires (CSentinelFor<TRangeSentinel<FBase>, TRangeIterator<TConditional<bOther, const V, V>>>)
NODISCARD FORCEINLINE constexpr bool operator==(const TCountedIterator<TRangeIterator<TConditional<bOther, const V, V>>>& InValue)
{
return InValue.Num() == 0 || InValue.GetBase() == Current;
}
NODISCARD FORCEINLINE constexpr TRangeSentinel<FBase> GetBase() const { return Current; }
private:
NO_UNIQUE_ADDRESS TRangeSentinel<FBase> Current;
FORCEINLINE constexpr FSentinelImpl(TRangeSentinel<FBase> InCurrent) : Current(InCurrent) { }
friend TTakeView;
};
};
template <typename R>
TTakeView(R&&, size_t) -> TTakeView<TAllView<R>>;
static_assert( CInputRange<TTakeView<TAllView<IRange< IInputIterator<int&>>>>>);
static_assert( CForwardRange<TTakeView<TAllView<IRange< IForwardIterator<int&>>>>>);
static_assert(CBidirectionalRange<TTakeView<TAllView<IRange<IBidirectionalIterator<int&>>>>>);
static_assert( CRandomAccessRange<TTakeView<TAllView<IRange< IRandomAccessIterator<int&>>>>>);
static_assert( CContiguousRange<TTakeView<TAllView<IRange< IContiguousIterator<int&>>>>>);
static_assert(CCommonRange<TTakeView<TAllView<ISizedRange< IRandomAccessIterator<int>>>>>);
static_assert( CSizedRange<TTakeView<TAllView<ISizedRange<IInputOrOutputIterator<int>>>>>);
static_assert( CView<TTakeView<TAllView< IRange<IInputOrOutputIterator<int>>>>>);
static_assert(COutputRange<TTakeView<TAllView<IRange<IOutputIterator<int&>>>>, int>);
NAMESPACE_END(Ranges)
template <typename T>
constexpr bool bEnableBorrowedRange<Ranges::TTakeView<T>> = bEnableBorrowedRange<T>;
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>()); })
NODISCARD FORCEINLINE constexpr auto Take(R&& Base, size_t Count)
{
return TTakeView(Forward<R>(Base), 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 { Ranges::Take(DeclVal<R>(), DeclVal<size_t>()); }) (R&& Base, size_t Count)
{
return Ranges::Take(Forward<R>(Base), Count);
});
return TAdaptorClosure<FClosure, size_t>(Count);
}
NAMESPACE_END(Ranges)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View 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

View File

@ -0,0 +1,236 @@
#pragma once
#include "CoreTypes.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"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Ranges)
/**
* A view adapter of a sequence that applies a transformation function to each element.
* When based on an input view, the transform view satisfies at least an input view up to a random access view.
* When based on a common view, the transform view satisfies a common view. When based on a sized view,
* the transform view satisfies a sized view. When based on a forward view and the function return
* an assignable value, the transform view satisfies an output view.
*/
template <CInputRange V, CMoveConstructible F> requires (CView<V> && CObject<F>
&& CRegularInvocable<F&, TRangeReference<V>> && CReferenceable<TInvokeResult<F&, TRangeReference<V>>>)
class TTransformView : public IBasicViewInterface<TTransformView<V, F>>
{
private:
template <bool bConst> class FIteratorImpl;
template <bool bConst> class FSentinelImpl;
public:
FORCEINLINE constexpr TTransformView() requires (CDefaultConstructible<V>&& CDefaultConstructible<F>) = default;
FORCEINLINE constexpr explicit TTransformView(V InBase, F InFunc) : Base(MoveTemp(InBase)), Func(MoveTemp(InFunc)) { }
NODISCARD FORCEINLINE constexpr auto Begin()
{
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, Ranges::Begin(Base));
}
NODISCARD FORCEINLINE constexpr auto End()
{
if constexpr (CCommonRange<V>)
{
return FIteratorImpl<false>(*this, Ranges::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, Ranges::End(Base));
}
else return FSentinelImpl<true>(*this, Ranges::End(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); }
private:
NO_UNIQUE_ADDRESS V Base;
NO_UNIQUE_ADDRESS F Func;
template <bool bConst>
class FIteratorImpl
{
private:
using FOwner = TConditional<bConst, const TTransformView, TTransformView>;
using FBase = TConditional<bConst, const V, V>;
using FFunc = TConditional<bConst, const F, F>;
public:
using FElementType = TRemoveCVRef<TInvokeResult<FFunc&, TRangeReference<FBase>>>;
FORCEINLINE constexpr FIteratorImpl() requires (CDefaultConstructible<TRangeIterator<FBase>>) = default;
FORCEINLINE constexpr FIteratorImpl(FIteratorImpl<!bConst> Iter) requires (bConst && CConvertibleTo<TRangeIterator<V>, TRangeIterator<FBase>>)
: Owner(Iter.Owner), Current(MoveTemp(Iter).GetBase())
{ }
NODISCARD friend FORCEINLINE constexpr bool operator==(const FIteratorImpl& LHS, const FIteratorImpl& RHS) requires (CEqualityComparable<TRangeIterator<FBase>>)
{
return LHS.GetBase() == RHS.GetBase();
}
NODISCARD friend FORCEINLINE constexpr auto operator<=>(const FIteratorImpl& LHS, const FIteratorImpl& RHS) requires (CThreeWayComparable<TRangeIterator<FBase>>)
{
return LHS.GetBase() <=> RHS.GetBase();
}
NODISCARD FORCEINLINE constexpr decltype(auto) operator*() const { return Invoke(Owner->Func, *GetBase()); }
NODISCARD FORCEINLINE constexpr decltype(auto) operator[](ptrdiff Index) const requires (CRandomAccessRange<FBase>) { return Invoke(Owner->Func, GetBase()[Index]); }
FORCEINLINE constexpr FIteratorImpl& operator++() { ++Current; return *this; }
FORCEINLINE constexpr FIteratorImpl& operator--() requires (CBidirectionalRange<FBase>) { --Current; return *this; }
FORCEINLINE constexpr void operator++(int) { ++*this; }
FORCEINLINE constexpr FIteratorImpl operator++(int) requires (CForwardRange<FBase>) { FIteratorImpl Temp = *this; ++*this; return Temp; }
FORCEINLINE constexpr FIteratorImpl operator--(int) requires (CBidirectionalRange<FBase>) { FIteratorImpl Temp = *this; --*this; return Temp; }
FORCEINLINE constexpr FIteratorImpl& operator+=(ptrdiff Offset) requires (CRandomAccessRange<FBase>) { Current += Offset; return *this; }
FORCEINLINE constexpr FIteratorImpl& operator-=(ptrdiff Offset) requires (CRandomAccessRange<FBase>) { Current -= Offset; return *this; }
NODISCARD FORCEINLINE constexpr FIteratorImpl operator+(ptrdiff Offset) const requires (CRandomAccessRange<FBase>) { FIteratorImpl Temp = *this; Temp += Offset; return Temp; }
NODISCARD FORCEINLINE constexpr FIteratorImpl operator-(ptrdiff Offset) const requires (CRandomAccessRange<FBase>) { FIteratorImpl Temp = *this; Temp -= Offset; return Temp; }
NODISCARD friend FORCEINLINE constexpr FIteratorImpl operator+(ptrdiff Offset, const FIteratorImpl& Iter) requires (CRandomAccessRange<FBase>) { return Iter + Offset; }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FIteratorImpl& LHS, const FIteratorImpl& RHS) requires (CSizedSentinelFor<TRangeIterator<FBase>, TRangeIterator<FBase>>)
{
return LHS.GetBase() - RHS.GetBase();
}
NODISCARD FORCEINLINE constexpr const TRangeIterator<FBase>& GetBase() const& { return Current; }
NODISCARD FORCEINLINE constexpr TRangeIterator<FBase> GetBase() && { return MoveTemp(Current); }
private:
NO_UNIQUE_ADDRESS FOwner* Owner;
NO_UNIQUE_ADDRESS TRangeIterator<FBase> Current;
FORCEINLINE constexpr FIteratorImpl(FOwner& InOwner, TRangeIterator<FBase> InCurrent) : Owner(&InOwner), Current(MoveTemp(InCurrent)) { }
template <bool> friend class FIteratorImpl;
template <bool> friend class FSentinelImpl;
friend TTransformView;
};
template <bool bConst>
class FSentinelImpl
{
private:
using FOwner = TConditional<bConst, const TTransformView, TTransformView>;
using FBase = TConditional<bConst, const V, V>;
public:
FORCEINLINE constexpr FSentinelImpl() requires (CDefaultConstructible<TRangeSentinel<FBase>>) = default;
FORCEINLINE constexpr FSentinelImpl(FSentinelImpl<!bConst> Sentinel) requires (bConst && CConvertibleTo<TRangeSentinel<V>, TRangeSentinel<FBase>>)
: Current(Sentinel.GetBase())
{ }
NODISCARD FORCEINLINE constexpr bool operator==(const FIteratorImpl<bConst>& InValue) const& { return Current == InValue.GetBase(); }
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FIteratorImpl<bConst>& LHS, const FSentinelImpl& RHS)
requires CSizedSentinelFor<TRangeSentinel<FBase>, TRangeIterator<FBase>>
{
return LHS.GetBase() - RHS.GetBase();
}
NODISCARD friend FORCEINLINE constexpr ptrdiff operator-(const FSentinelImpl& LHS, const FIteratorImpl<bConst>& RHS)
requires CSizedSentinelFor<TRangeSentinel<FBase>, TRangeIterator<FBase>>
{
return LHS.GetBase() - RHS.GetBase();
}
NODISCARD FORCEINLINE constexpr TRangeSentinel<FBase> GetBase() const { return Current; }
private:
NO_UNIQUE_ADDRESS TRangeSentinel<FBase> Current;
FORCEINLINE constexpr FSentinelImpl(FOwner& InOwner, TRangeSentinel<FBase> InCurrent) : Current(InCurrent) { }
friend TTransformView;
};
};
template <typename R, typename F>
TTransformView(R&&, F) -> TTransformView<TAllView<R>, F>;
static_assert( CInputRange<TTransformView<TAllView<IRange< IInputIterator<int&>>>, int(*)(int)>>);
static_assert( CForwardRange<TTransformView<TAllView<IRange< IForwardIterator<int&>>>, int(*)(int)>>);
static_assert(CBidirectionalRange<TTransformView<TAllView<IRange<IBidirectionalIterator<int&>>>, int(*)(int)>>);
static_assert( CRandomAccessRange<TTransformView<TAllView<IRange< IRandomAccessIterator<int&>>>, int(*)(int)>>);
static_assert( CRandomAccessRange<TTransformView<TAllView<IRange< IContiguousIterator<int&>>>, int(*)(int)>>);
static_assert(CCommonRange<TTransformView<TAllView<ICommonRange<IForwardIterator<int>>>, int(*)(int)>>);
static_assert( CSizedRange<TTransformView<TAllView< ISizedRange< IInputIterator<int>>>, int(*)(int)>>);
static_assert( CView<TTransformView<TAllView< IRange< IInputIterator<int>>>, int(*)(int)>>);
static_assert(COutputRange<TTransformView<TAllView<IRange<IForwardIterator<int>>>, int&(*)(int)>, int>);
NAMESPACE_END(Ranges)
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>()); })
NODISCARD FORCEINLINE constexpr auto Transform(R&& Base, F&& Func)
{
return TTransformView(Forward<R>(Base), Forward<F>(Func));
}
/** Creates A view adapter of a sequence that applies a transformation function to each element. */
template <typename F>
NODISCARD FORCEINLINE constexpr auto Transform(F&& Func)
{
using FClosure = decltype([]<CViewableRange R, typename T> requires (requires { Ranges::Transform(DeclVal<R>(), DeclVal<T>()); }) (R&& Base, T&& Func)
{
return Ranges::Transform(Forward<R>(Base), Forward<T>(Func));
});
return TAdaptorClosure<FClosure, TDecay<F>>(Forward<F>(Func));
}
NAMESPACE_END(Ranges)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -1,9 +1,12 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Templates/Utility.h"
#include "Iterator/Iterator.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.h"
#include "Iterators/Utility.h"
#include "Iterators/BasicIterator.h"
#include "Iterators/Sentinel.h"
#include "Iterators/ReverseIterator.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Redcraft)
@ -17,7 +20,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
template <typename R> template <typename R>
inline constexpr bool bEnableBorrowedRange = false; inline constexpr bool bEnableBorrowedRange = false;
NAMESPACE_BEGIN(Range) NAMESPACE_BEGIN(Ranges)
/** @return The iterator to the beginning of a container. */ /** @return The iterator to the beginning of a container. */
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>) template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
@ -37,18 +40,17 @@ NODISCARD FORCEINLINE constexpr auto Begin(T&& Container)
/** Overloads the Begin algorithm for initializer_list. */ /** Overloads the Begin algorithm for initializer_list. */
template <typename T> template <typename T>
NODISCARD FORCEINLINE constexpr auto Begin(initializer_list<T>& Container) NODISCARD FORCEINLINE constexpr const T* Begin(initializer_list<T>& Container)
{ {
return Container.begin(); return Container.begin();
} }
NAMESPACE_END(Range) NAMESPACE_END(Ranges)
template <typename R> template <typename R>
using TRangeIterator = decltype(Range::Begin(DeclVal<R&>())); using TRangeIterator = decltype(Ranges::Begin(DeclVal<R&>()));
NAMESPACE_BEGIN(Ranges)
NAMESPACE_BEGIN(Range)
/** @return The iterator to the end of a container. */ /** @return The iterator to the end of a container. */
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>) template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
@ -68,18 +70,18 @@ NODISCARD FORCEINLINE constexpr auto End(T&& Container)
/** Overloads the End algorithm for initializer_list. */ /** Overloads the End algorithm for initializer_list. */
template <typename T> template <typename T>
NODISCARD FORCEINLINE constexpr auto End(initializer_list<T>& Container) NODISCARD FORCEINLINE constexpr const T* End(initializer_list<T>& Container)
{ {
return Container.end(); return Container.end();
} }
NAMESPACE_END(Range) NAMESPACE_END(Ranges)
template <typename R> 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. */ /** @return The reverse iterator to the beginning of a container. */
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>) template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
@ -95,12 +97,12 @@ template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRe
&& (CSameAs<TRangeIterator<T>, TRangeSentinel<T>> && CBidirectionalIterator<TRangeIterator<T>>)) && (CSameAs<TRangeIterator<T>, TRangeSentinel<T>> && CBidirectionalIterator<TRangeIterator<T>>))
NODISCARD FORCEINLINE constexpr auto RBegin(T&& Container) 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. */ /** @return The reverse iterator to the end of a container. */
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>) 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) NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
{ {
return Container.REnd(); return Container.REnd();
@ -108,14 +110,14 @@ NODISCARD FORCEINLINE constexpr auto REnd(T&& Container)
/** Overloads the REnd algorithm for synthesized. */ /** Overloads the REnd algorithm for synthesized. */
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>) 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>>)) && (CSameAs<TRangeIterator<T>, TRangeSentinel<T>> && CBidirectionalIterator<TRangeIterator<T>>))
NODISCARD FORCEINLINE constexpr auto REnd(T&& Container) 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> template <typename R>
using TRangeElement = TIteratorElement<TRangeIterator<R>>; using TRangeElement = TIteratorElement<TRangeIterator<R>>;
@ -129,7 +131,7 @@ using TRangeReference = TIteratorReference<TRangeIterator<R>>;
template <typename R> template <typename R>
using TRangeRValueReference = TIteratorRValueReference<TRangeIterator<R>>; using TRangeRValueReference = TIteratorRValueReference<TRangeIterator<R>>;
NAMESPACE_BEGIN(Range) NAMESPACE_BEGIN(Ranges)
/** @return The pointer to the container element storage. */ /** @return The pointer to the container element storage. */
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>) template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
@ -142,19 +144,19 @@ NODISCARD FORCEINLINE constexpr auto GetData(T&& Container)
/** Overloads the GetData algorithm for synthesized. */ /** Overloads the GetData algorithm for synthesized. */
template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>) template <typename T> requires ((CLValueReference<T> || bEnableBorrowedRange<TRemoveCVRef<T>>)
&& !requires(T&& Container) { { Container.GetData() } -> CSameAs<TAddPointer<TRangeReference<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) 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. */ /** Disable the CSizedRange concept for specific types. */
template <typename R> template <typename R>
inline constexpr bool bDisableSizedRange = false; inline constexpr bool bDisableSizedRange = false;
NAMESPACE_BEGIN(Range) NAMESPACE_BEGIN(Ranges)
/** @return The number of elements in the container. */ /** @return The number of elements in the container. */
template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>> template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
@ -178,7 +180,14 @@ template <typename T> requires (!bDisableSizedRange<TRemoveCVRef<T>>
&& CSizedSentinelFor<TRangeSentinel<T>, TRangeIterator<T>> && CForwardIterator<TRangeIterator<T>>) && CSizedSentinelFor<TRangeSentinel<T>, TRangeIterator<T>> && CForwardIterator<TRangeIterator<T>>)
NODISCARD FORCEINLINE constexpr size_t Num(T&& Container) 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. */
template <typename T>
NODISCARD FORCEINLINE constexpr size_t Num(initializer_list<T>& Container)
{
return Container.size();
} }
/** @return true if the container is empty, false otherwise. */ /** @return true if the container is empty, false otherwise. */
@ -194,7 +203,7 @@ template <typename T> requires ((CBoundedArray<TRemoveReference<T>>
&& !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; }) && !requires(T&& Container) { { Container.IsEmpty() } -> CBooleanTestable; })
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container) 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. */ /** Overloads the IsEmpty algorithm for synthesized. */
@ -204,14 +213,19 @@ template <typename T> requires (!CBoundedArray<TRemoveReference<T>>
&& CForwardIterator<TRangeIterator<T>>) && CForwardIterator<TRangeIterator<T>>)
NODISCARD FORCEINLINE constexpr bool IsEmpty(T&& Container) 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 concept specifies a type is a range.
* A range is an iterator-sentinel pair that represents a sequence of elements. * 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
* 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.
*/ */
template <typename R> template <typename R>
concept CRange = concept CRange =
@ -248,28 +262,27 @@ concept CBorrowedRange = CRange<R> && (CLValueReference<R> || bEnableBorrowedRan
/** /**
* A concept specifies a type is a sized range. * 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 * Indicates the expression 'Ranges::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 * without modifying the range object. A sized range may support fetched size before fetched iterator-sentinel pair
* the range is an input iterator. Indirect calculation of the range by obtaining the iterator * if the range does not satisfy the forward range, otherwise it is equality-preserving.
* may cause the range to become invalid, that is, the iterator cannot be obtained again.
*/ */
template <typename R> template <typename R>
concept CSizedRange = CRange<R> concept CSizedRange = CRange<R>
&& requires(R Range) && 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. */ /** This is an example of a sized range type, indicate the traits that define a sized range type. */
template <CInputOrOutputIterator I, CSizedSentinelFor<I> S = ISizedSentinelFor<I>> template <CInputOrOutputIterator I, CSizedSentinelFor<I> S = ISizedSentinelFor<I>>
struct ISizedRange /* : IRange<I, S> */ struct ISizedRange /* : IRange<I, S> */
{ {
// ~Begin CRange // ~Begin CRange.
I Begin() /* const */; I Begin() /* const */;
S End() /* const */; S End() /* const */;
// ~End CRange // ~End CRange.
/** /**
* Get the number of elements in the range. * Get the number of elements in the range.
@ -324,24 +337,24 @@ template <typename R>
concept CContiguousRange = CRandomAccessRange<R> && CContiguousIterator<TRangeIterator<R>> concept CContiguousRange = CRandomAccessRange<R> && CContiguousIterator<TRangeIterator<R>>
&& requires(R& Range) && 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. */ /** This is an example of a contiguous range type, indicate the traits that define a contiguous range type. */
template <CContiguousIterator I, CSentinelFor<I> S = ISentinelFor<I>> template <CContiguousIterator I, CSentinelFor<I> S = ISentinelFor<I>>
struct IContiguousRange /* : IRange<I, S> */ struct IContiguousRange /* : IRange<I, S> */
{ {
// ~Begin CRange // ~Begin CRange.
I Begin() /* const */; I Begin() /* const */;
S End() /* const */; S End() /* const */;
// ~End CRange // ~End CRange.
/** /**
* Get the pointer to the container element storage. * Get the pointer to the container element storage.
* The function is optional if the range size can be computed indirectly from the iterator. * 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. * must be satisfied to always be true.
* If the function is const, it means that the const IContiguousRange satisfies CContiguousRange. * If the function is const, it means that the const IContiguousRange satisfies CContiguousRange.
*/ */
@ -351,16 +364,16 @@ struct IContiguousRange /* : IRange<I, S> */
// Use IContiguousRange<...> represents a contiguous range type. // Use IContiguousRange<...> represents a contiguous range type.
static_assert(CContiguousRange<IContiguousRange<IContiguousIterator<int&>>>); static_assert(CContiguousRange<IContiguousRange<IContiguousIterator<int&>>>);
/** A concept specifies a type is a range and its iterators and sentinel types are the same. */ /** A concept specifies a type is a range and its iterator and sentinel types are the same. */
template <typename R> template <typename R>
concept CCommonRange = CRange<R> && CSameAs<TRangeIterator<R>, TRangeSentinel<R>>; concept CCommonRange = CRange<R> && CSameAs<TRangeIterator<R>, TRangeSentinel<R>>;
/** This is an example of a common range type, indicate the traits that define a common range type. */ /** This is an example of a common range type, indicate the traits that define a common range type. */
template <CForwardIterator I> template <CForwardIterator I>
using TCommonRange = IRange<I, I>; using ICommonRange = IRange<I, I>;
// Use TCommonRange<...> represents a common range type. // Use TCommonRange<...> represents a common range type.
static_assert(CCommonRange<TCommonRange<IForwardIterator<int&>>>); static_assert(CCommonRange<ICommonRange<IForwardIterator<int&>>>);
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)

View File

@ -0,0 +1,156 @@
#pragma once
#include "CoreTypes.h"
#include "TypeTraits/TypeTraits.h"
#include "Templates/Utility.h"
#include "Iterators/Utility.h"
#include "Iterators/Sentinel.h"
#include "Iterators/BasicIterator.h"
#include "Iterators/ReverseIterator.h"
#include "Memory/Address.h"
#include "Ranges/Utility.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Ranges)
/** An interface class template for defining a view. Not directly instantiable. */
template <CClass T> requires (CSameAs<T, TRemoveCV<T>>)
class IBasicViewInterface
{
public:
/** @return The pointer to the underlying element storage. */
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(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 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 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 { 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 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 *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 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.
private:
FORCEINLINE constexpr IBasicViewInterface() = default;
FORCEINLINE constexpr IBasicViewInterface(const IBasicViewInterface&) = default;
FORCEINLINE constexpr IBasicViewInterface(IBasicViewInterface&&) = default;
FORCEINLINE constexpr IBasicViewInterface& operator=(const IBasicViewInterface&) = default;
FORCEINLINE constexpr IBasicViewInterface& operator=(IBasicViewInterface&&) = default;
FORCEINLINE constexpr ~IBasicViewInterface() = default;
friend T;
};
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, Ranges::IBasicViewInterface<TRemoveCVRef<V>>>;
NAMESPACE_PRIVATE_BEGIN
template <typename T> struct TIsInitializerList : FFalse { };
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 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))));
/** 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>
class TRangeView : public IBasicViewInterface<TRangeView<I, S>>
{
public:
FORCEINLINE constexpr TRangeView() requires (CDefaultConstructible<I>) = default;
FORCEINLINE constexpr TRangeView(I InFirst, S InLast) : First(MoveTemp(InFirst)), Last(InLast) { }
NODISCARD FORCEINLINE constexpr I Begin() requires (!CCopyable<I>) { return MoveTemp(First); }
NODISCARD FORCEINLINE constexpr I Begin() const requires ( CCopyable<I>) { return First; }
NODISCARD FORCEINLINE constexpr S End() const { return Last; }
NODISCARD FORCEINLINE constexpr size_t Num() const requires (CSizedSentinelFor<S, I>) { return Last - First; }
NODISCARD FORCEINLINE constexpr bool IsEmpty() const { return First == Last; }
private:
NO_UNIQUE_ADDRESS I First;
NO_UNIQUE_ADDRESS S Last;
};
template <CInputOrOutputIterator I, CSentinelFor<I> S>
TRangeView(I, S) -> TRangeView<I, S>;
NAMESPACE_END(Ranges)
template <typename I, typename S>
constexpr bool bEnableBorrowedRange<Ranges::TRangeView<I, S>> = true;
NAMESPACE_BEGIN(Ranges)
/** Creates A simple view that combines an iterator-sentinel pair. */
template <CInputOrOutputIterator I, CSentinelFor<I> S = I>
NODISCARD FORCEINLINE constexpr TRangeView<I, S> View(I First, S Last)
{
return TRangeView<I, S>(MoveTemp(First), Last);
}
NAMESPACE_END(Ranges)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

File diff suppressed because it is too large Load Diff

View File

@ -1,690 +0,0 @@
#pragma once
#include "CoreTypes.h"
#include "String/Char.h"
#include "Memory/Allocator.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "Containers/ArrayView.h"
#include "TypeTraits/TypeTraits.h"
#include "Memory/MemoryOperator.h"
#include "Miscellaneous/Iterator.h"
#include "Miscellaneous/Container.h"
#include "Miscellaneous/AssertionMacros.h"
#include "Miscellaneous/ConstantIterator.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 Super = TArrayView<const T>;
public:
using ElementType = T;
using Reference = typename Super::Reference;
using Iterator = typename Super::Iterator;
using ReverseIterator = typename Super::ReverseIterator;
static_assert(CContiguousIterator<Iterator>);
/** 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<TIteratorElementType<I>(*)[], const ElementType(*)[]>)
FORCEINLINE constexpr TStringView(I InFirst, size_t InCount) : Super(InFirst, InCount) { }
/** Constructs a string view that is a view over the range ['InFirst', 'InLast'). */
template <CContiguousIterator I, CSizedSentinelFor<I> S> requires (CConvertibleTo<TIteratorElementType<I>(*)[], const ElementType(*)[]>)
FORCEINLINE constexpr TStringView(I InFirst, S InLast) : Super(InFirst, InLast) { }
/** Constructs a string view that is a view over the string 'InString'. */
template <typename Allocator>
FORCEINLINE constexpr TStringView(const TString<ElementType, Allocator>& InString);
/** Constructs a string view that is a view over the range ['InPtr', 'InPtr' + 'Count'). */
FORCEINLINE constexpr TStringView(const ElementType* InPtr, size_t Count) : Super(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 ElementType* InPtr)
{
checkf(InPtr != nullptr, TEXT("TStringView cannot be initialized by nullptr. Please check the pointer."));
size_t Length = 0;
if constexpr (CSameAs<ElementType, char>)
{
Length = NAMESPACE_STD::strlen(InPtr);
}
else if constexpr (CSameAs<ElementType, wchar>)
{
Length = NAMESPACE_STD::wcslen(InPtr);
}
else
{
while (InPtr[Length] != LITERAL(ElementType, '\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<Super>(LHS) == static_cast<Super>(RHS); }
/** Compares the contents of a string view and a character. */
NODISCARD friend constexpr bool operator==(TStringView LHS, ElementType RHS) { return LHS == TStringView(&RHS, 1); }
NODISCARD friend constexpr bool operator==(ElementType 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<Super>(LHS) <=> static_cast<Super>(RHS); }
/** Compares the contents of a string view and a character. */
NODISCARD friend constexpr auto operator<=>(TStringView LHS, ElementType RHS) { return LHS <=> TStringView(&RHS, 1); }
NODISCARD friend constexpr auto operator<=>(ElementType 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([](ElementType Char) { return !TChar<ElementType>::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([](ElementType Char) { return !TChar<ElementType>::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(ElementType, '\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(ElementType* 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."));
Super 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(ElementType 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(ElementType 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(ElementType Char) const
{
return Find(Char) != INDEX_NONE;
}
/** @return true if the string view contains character that satisfy the given predicate, false otherwise. */
template <CPredicate<ElementType> 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(ElementType 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<ElementType> 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(ElementType 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<ElementType> 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](ElementType 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(ElementType 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](ElementType 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(ElementType 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](ElementType 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(ElementType Char, size_t Index = 0) const
{
return Find([Char](ElementType 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](ElementType 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(ElementType Char, size_t Index = INDEX_NONE) const
{
return RFind([Char](ElementType 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(ElementType, '\0') || Contains(LITERAL(ElementType, '\0')))
{
return NAMESPACE_PRIVATE::TCStringFromTStringView<ElementType>(this->GetData(), false);
}
ElementType* Buffer = new ElementType[this->Num() + 1];
Copy(Buffer);
Buffer[this->Num()] = LITERAL(ElementType, '\0');
return NAMESPACE_PRIVATE::TCStringFromTStringView<ElementType>(Buffer, true);
}
public:
/** @return true if the string only contains valid characters, false otherwise. */
NODISCARD constexpr bool IsValid() const
{
for (ElementType Char : *this)
{
if (!TChar<ElementType>::IsValid(Char)) return false;
}
return true;
}
/** @return true if the string only contains ASCII characters, false otherwise. */
NODISCARD constexpr bool IsASCII() const
{
for (ElementType Char : *this)
{
if (!TChar<ElementType>::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(ElementType, '-')))
{
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(ElementType, '-')))
{
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<Super>(A)); }
};
template <typename I, typename S>
TStringView(I, S) -> TStringView<TIteratorElementType<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>;
#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))
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -57,7 +57,7 @@ struct TLiteral<u32char>
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
/** Templated literal struct to allow selection of string literals based on the character type provided, and not on compiler switches. */ /** 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<u8char>, "TChar assumes u8char is an unsigned integer");
static_assert(CUnsigned<u16char>, "TChar assumes u16char is an unsigned integer"); static_assert(CUnsigned<u16char>, "TChar assumes u16char is an unsigned integer");
@ -68,31 +68,38 @@ static_assert(CUnsigned<unicodechar>, "TChar assumes unicodechar is an unsigned
template <CCharType T> template <CCharType T>
struct TChar struct TChar
{ {
using CharType = T; using FCharType = T;
/** The maximum number of code units required to represent a single character. if unknown, guess 1. */ /** The maximum number of code units required to represent a single character. if unknown, guess 1. */
static constexpr size_t MaxCodeUnitLength = static constexpr size_t MaxCodeUnitLength =
CSameAs<CharType, char> ? MB_LEN_MAX : CSameAs<FCharType, char> ? MB_LEN_MAX :
CSameAs<CharType, wchar> ? CSameAs<FCharType, wchar> ?
PLATFORM_WINDOWS ? 2 : PLATFORM_WINDOWS ? 2 :
PLATFORM_LINUX ? 1 : 1 : PLATFORM_LINUX ? 1 : 1 :
CSameAs<CharType, u8char> ? 4 : CSameAs<FCharType, u8char> ? 4 :
CSameAs<CharType, u16char> ? 2 : CSameAs<FCharType, u16char> ? 2 :
CSameAs<CharType, u32char> ? 1 : 1; CSameAs<FCharType, u32char> ? 1 : 1;
/** Whether the character type is fixed-length. */ /** Whether the character type is fixed-length. */
static constexpr bool bIsFixedLength = MaxCodeUnitLength == 1; static constexpr bool bIsFixedLength = MaxCodeUnitLength == 1;
NODISCARD FORCEINLINE static constexpr bool IsValid(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsValid(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, 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; if ((InChar & 0b10000000) == 0b00000000) return true;
return false; return false;
} }
else if constexpr (CSameAs<CharType, u16char> || CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u16char> || CSameAs<FCharType, u32char>)
{ {
if (InChar >= 0xD800 && InChar <= 0xDBFF) return false; if (InChar >= 0xD800 && InChar <= 0xDBFF) return false;
if (InChar >= 0xDC00 && InChar <= 0xDFFF) return false; if (InChar >= 0xDC00 && InChar <= 0xDFFF) return false;
@ -101,30 +108,30 @@ struct TChar
} }
// Windows uses UTF-16 encoding for wchar. // Windows uses UTF-16 encoding for wchar.
else if constexpr (PLATFORM_WINDOWS && (CSameAs<CharType, 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. // Linux uses UTF-32 encoding for wchar.
else if constexpr (PLATFORM_LINUX && (CSameAs<CharType, 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(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsNonch(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsNonch(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, u8char>) if constexpr (CSameAs<FCharType, u8char>)
{ {
return false; return false;
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
if (InChar >= U16TEXT('\uFDD0') && InChar <= U16TEXT('\uFDEF')) return true; if (InChar >= U16TEXT('\uFDD0') && InChar <= U16TEXT('\uFDEF')) return true;
@ -134,7 +141,7 @@ struct TChar
return false; return false;
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
if (InChar >= U32TEXT('\uFDD0') && InChar <= U32TEXT('\uFDEF')) return true; if (InChar >= U32TEXT('\uFDD0') && InChar <= U32TEXT('\uFDEF')) return true;
@ -144,25 +151,25 @@ struct TChar
} }
// Windows uses UTF-16 encoding for wchar. // Windows uses UTF-16 encoding for wchar.
else if constexpr (PLATFORM_WINDOWS && (CSameAs<CharType, 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. // Linux uses UTF-32 encoding for wchar.
else if constexpr (PLATFORM_LINUX && (CSameAs<CharType, 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(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsASCII(CharType InChar = LITERAL(CharType, '\0')) NODISCARD FORCEINLINE static constexpr bool IsASCII(FCharType InChar = LITERAL(FCharType, '\0'))
{ {
if constexpr (CSameAs<CharType, char>) if constexpr (CSameAs<FCharType, char>)
{ {
constexpr bool ASCIICompatible = []() -> bool constexpr bool ASCIICompatible = []() -> bool
{ {
@ -188,7 +195,7 @@ struct TChar
return ASCIICompatible && 0x00 <= InChar && InChar <= 0x7F; return ASCIICompatible && 0x00 <= InChar && InChar <= 0x7F;
} }
else if constexpr (CSameAs<CharType, wchar>) else if constexpr (CSameAs<FCharType, wchar>)
{ {
constexpr bool ASCIICompatible = []() -> bool constexpr bool ASCIICompatible = []() -> bool
{ {
@ -214,19 +221,19 @@ struct TChar
return ASCIICompatible && 0x00 <= InChar && InChar <= 0x7F; return ASCIICompatible && 0x00 <= InChar && InChar <= 0x7F;
} }
else if constexpr (CSameAs<CharType, u8char> || CSameAs<CharType, u16char> || CSameAs<CharType, u32char> || CSameAs<CharType, unicodechar>) else if constexpr (CSameAs<FCharType, u8char> || CSameAs<FCharType, u16char> || CSameAs<FCharType, u32char> || CSameAs<FCharType, unicodechar>)
{ {
return InChar <= 0x7F; return InChar <= 0x7F;
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsAlnum(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsAlnum(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return NAMESPACE_STD::isalnum(InChar, Loc); return NAMESPACE_STD::isalnum(InChar, Loc);
@ -237,15 +244,15 @@ struct TChar
} }
} }
NODISCARD FORCEINLINE static constexpr bool IsAlpha(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsAlpha(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return NAMESPACE_STD::isalpha(InChar, Loc); return NAMESPACE_STD::isalpha(InChar, Loc);
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* /*
* BASIC LATIN * BASIC LATIN
@ -258,29 +265,29 @@ struct TChar
return false; return false;
} }
else if constexpr (CSameAs<CharType, u16char> || CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u16char> || CSameAs<FCharType, u32char>)
{ {
checkf(InChar <= LITERAL(CharType, '\u007F'), TEXT("TChar::IsAlpha() only supports basic latin block.")); checkf(InChar <= LITERAL(FCharType, '\u007F'), TEXT("TChar::IsAlpha() only supports basic latin block."));
if (InChar > LITERAL(CharType, '\u007F')) return false; if (InChar > LITERAL(FCharType, '\u007F')) return false;
return TChar<u8char>::IsAlpha(static_cast<u8char>(InChar)); return TChar<u8char>::IsAlpha(static_cast<u8char>(InChar));
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsLower(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsLower(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return NAMESPACE_STD::islower(InChar, Loc); return NAMESPACE_STD::islower(InChar, Loc);
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* /*
* BASIC LATIN * BASIC LATIN
@ -291,7 +298,7 @@ struct TChar
return false; return false;
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsLower() only supports basic latin block.")); checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsLower() only supports basic latin block."));
@ -300,7 +307,7 @@ struct TChar
return TChar<u8char>::IsLower(static_cast<u8char>(InChar)); return TChar<u8char>::IsLower(static_cast<u8char>(InChar));
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsLower() only supports basic latin block.")); checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsLower() only supports basic latin block."));
@ -309,20 +316,20 @@ struct TChar
return TChar<u8char>::IsLower(static_cast<u8char>(InChar)); return TChar<u8char>::IsLower(static_cast<u8char>(InChar));
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsUpper(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsUpper(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return NAMESPACE_STD::isupper(InChar, Loc); return NAMESPACE_STD::isupper(InChar, Loc);
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* /*
* BASIC LATIN * BASIC LATIN
@ -333,7 +340,7 @@ struct TChar
return false; return false;
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsUpper() only supports basic latin block.")); checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsUpper() only supports basic latin block."));
@ -342,7 +349,7 @@ struct TChar
return TChar<u8char>::IsUpper(static_cast<u8char>(InChar)); return TChar<u8char>::IsUpper(static_cast<u8char>(InChar));
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsUpper() only supports basic latin block.")); checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsUpper() only supports basic latin block."));
@ -351,20 +358,20 @@ struct TChar
return TChar<u8char>::IsUpper(static_cast<u8char>(InChar)); return TChar<u8char>::IsUpper(static_cast<u8char>(InChar));
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsDigit(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsDigit(FCharType InChar)
{ {
static_assert(TChar::IsASCII()); static_assert(TChar::IsASCII());
/* <U0030>..<U0039>; */ /* <U0030>..<U0039>; */
return InChar >= LITERAL(CharType, '0') && InChar <= LITERAL(CharType, '9'); return InChar >= LITERAL(FCharType, '0') && InChar <= LITERAL(FCharType, '9');
} }
NODISCARD FORCEINLINE static constexpr bool IsDigit(CharType InChar, unsigned Base) NODISCARD FORCEINLINE static constexpr bool IsDigit(FCharType InChar, unsigned Base)
{ {
checkf(Base >= 2 && Base <= 36, TEXT("Base must be in the range [2, 36].")); checkf(Base >= 2 && Base <= 36, TEXT("Base must be in the range [2, 36]."));
@ -373,32 +380,32 @@ struct TChar
bool bResult = false; bool bResult = false;
/* <U0030>..<U0039>; */ /* <U0030>..<U0039>; */
bResult |= InChar >= LITERAL(CharType, '0') && InChar < LITERAL(CharType, '0') + static_cast<signed>(Base); bResult |= InChar >= LITERAL(FCharType, '0') && InChar < LITERAL(FCharType, '0') + static_cast<signed>(Base);
/* <U0041>..<U0046>; */ /* <U0041>..<U0046>; */
bResult |= InChar >= LITERAL(CharType, 'a') && InChar < LITERAL(CharType, 'a') + static_cast<signed>(Base) - 10; bResult |= InChar >= LITERAL(FCharType, 'a') && InChar < LITERAL(FCharType, 'a') + static_cast<signed>(Base) - 10;
/* <U0061>..<U0066>; */ /* <U0061>..<U0066>; */
bResult |= InChar >= LITERAL(CharType, 'A') && InChar < LITERAL(CharType, 'A') + static_cast<signed>(Base) - 10; bResult |= InChar >= LITERAL(FCharType, 'A') && InChar < LITERAL(FCharType, 'A') + static_cast<signed>(Base) - 10;
return bResult; return bResult;
} }
NODISCARD FORCEINLINE static constexpr bool IsCntrl(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsCntrl(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return NAMESPACE_STD::iscntrl(InChar, Loc); return NAMESPACE_STD::iscntrl(InChar, Loc);
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* <U0000>..<U001F>;<U007F>; */ /* <U0000>..<U001F>;<U007F>; */
return (InChar >= U8TEXT('\u0000') && InChar <= U8TEXT('\u001F')) || InChar == U8TEXT('\u007F'); return (InChar >= U8TEXT('\u0000') && InChar <= U8TEXT('\u001F')) || InChar == U8TEXT('\u007F');
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
/* <U0000>..<U001F>;<U007F>..<U009F>;<U2028>;<U2029>; */ /* <U0000>..<U001F>;<U007F>..<U009F>;<U2028>;<U2029>; */
return return
@ -407,7 +414,7 @@ struct TChar
(InChar == U16TEXT('\u2028') || InChar == U16TEXT('\u2029')); (InChar == U16TEXT('\u2028') || InChar == U16TEXT('\u2029'));
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
/* <U0000>..<U001F>;<U007F>..<U009F>;<U2028>;<U2029>; */ /* <U0000>..<U001F>;<U007F>..<U009F>;<U2028>;<U2029>; */
return return
@ -416,20 +423,20 @@ struct TChar
(InChar == U32TEXT('\u2028') || InChar == U32TEXT('\u2029')); (InChar == U32TEXT('\u2028') || InChar == U32TEXT('\u2029'));
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsGraph(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsGraph(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return NAMESPACE_STD::isgraph(InChar, Loc); return NAMESPACE_STD::isgraph(InChar, Loc);
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* /*
* BASIC LATIN * BASIC LATIN
@ -440,7 +447,7 @@ struct TChar
return false; return false;
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsGraph() only supports basic latin block.")); checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsGraph() only supports basic latin block."));
@ -449,7 +456,7 @@ struct TChar
return TChar<u8char>::IsGraph(static_cast<u8char>(InChar)); return TChar<u8char>::IsGraph(static_cast<u8char>(InChar));
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsGraph() only supports basic latin block.")); checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsGraph() only supports basic latin block."));
@ -458,20 +465,20 @@ struct TChar
return TChar<u8char>::IsGraph(static_cast<u8char>(InChar)); return TChar<u8char>::IsGraph(static_cast<u8char>(InChar));
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsSpace(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsSpace(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return NAMESPACE_STD::isspace(InChar, Loc); return NAMESPACE_STD::isspace(InChar, Loc);
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* /*
* ISO/IEC 6429 * ISO/IEC 6429
@ -488,7 +495,7 @@ struct TChar
return false; return false;
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
/* /*
* ISO/IEC 6429 * ISO/IEC 6429
@ -533,7 +540,7 @@ struct TChar
return false; return false;
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
/* /*
* ISO/IEC 6429 * ISO/IEC 6429
@ -578,26 +585,26 @@ struct TChar
return false; return false;
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsBlank(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsBlank(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return NAMESPACE_STD::isblank(InChar, Loc); return NAMESPACE_STD::isblank(InChar, Loc);
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* <U0009>;<U0020>; */ /* <U0009>;<U0020>; */
return InChar == U8TEXT('\u0009') || InChar == U8TEXT('\u0020'); return InChar == U8TEXT('\u0009') || InChar == U8TEXT('\u0020');
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
/* <U0009>;<U0020>;<U1680>;<U180E>;<U2000>..<U2006>;<U2008>..<U200A>;<U205F>;<U3000>; */ /* <U0009>;<U0020>;<U1680>;<U180E>;<U2000>..<U2006>;<U2008>..<U200A>;<U205F>;<U3000>; */
return return
@ -608,7 +615,7 @@ struct TChar
(InChar == U16TEXT('\u205F') || InChar == U16TEXT('\u3000')); (InChar == U16TEXT('\u205F') || InChar == U16TEXT('\u3000'));
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
/* <U0009>;<U0020>;<U1680>;<U180E>;<U2000>..<U2006>;<U2008>..<U200A>;<U205F>;<U3000>; */ /* <U0009>;<U0020>;<U1680>;<U180E>;<U2000>..<U2006>;<U2008>..<U200A>;<U205F>;<U3000>; */
return return
@ -619,20 +626,20 @@ struct TChar
(InChar == U32TEXT('\u205F') || InChar == U32TEXT('\u3000')); (InChar == U32TEXT('\u205F') || InChar == U32TEXT('\u3000'));
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsPrint(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsPrint(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return NAMESPACE_STD::isprint(InChar, Loc); return NAMESPACE_STD::isprint(InChar, Loc);
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* /*
* BASIC LATIN * BASIC LATIN
@ -643,7 +650,7 @@ struct TChar
return false; return false;
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsPrint() only supports basic latin block.")); checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsPrint() only supports basic latin block."));
@ -652,7 +659,7 @@ struct TChar
return TChar<u8char>::IsPrint(static_cast<u8char>(InChar)); return TChar<u8char>::IsPrint(static_cast<u8char>(InChar));
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsPrint() only supports basic latin block.")); checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsPrint() only supports basic latin block."));
@ -661,20 +668,20 @@ struct TChar
return TChar<u8char>::IsPrint(static_cast<u8char>(InChar)); return TChar<u8char>::IsPrint(static_cast<u8char>(InChar));
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr bool IsPunct(CharType InChar) NODISCARD FORCEINLINE static constexpr bool IsPunct(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return NAMESPACE_STD::ispunct(InChar, Loc); return NAMESPACE_STD::ispunct(InChar, Loc);
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* /*
* BASIC LATIN * BASIC LATIN
@ -689,7 +696,7 @@ struct TChar
return false; return false;
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsPunct() only supports basic latin block.")); checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::IsPunct() only supports basic latin block."));
@ -698,7 +705,7 @@ struct TChar
return TChar<u8char>::IsPunct(static_cast<u8char>(InChar)); return TChar<u8char>::IsPunct(static_cast<u8char>(InChar));
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsPunct() only supports basic latin block.")); checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::IsPunct() only supports basic latin block."));
@ -707,20 +714,20 @@ struct TChar
return TChar<u8char>::IsPunct(static_cast<u8char>(InChar)); return TChar<u8char>::IsPunct(static_cast<u8char>(InChar));
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return false; return false;
} }
NODISCARD FORCEINLINE static constexpr CharType ToLower(CharType InChar) NODISCARD FORCEINLINE static constexpr FCharType ToLower(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return static_cast<CharType>(NAMESPACE_STD::tolower(InChar, Loc)); return static_cast<FCharType>(NAMESPACE_STD::tolower(InChar, Loc));
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* /*
* BASIC LATIN * BASIC LATIN
@ -737,7 +744,7 @@ struct TChar
return InChar; return InChar;
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::ToLower() only supports basic latin block.")); checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::ToLower() only supports basic latin block."));
@ -746,7 +753,7 @@ struct TChar
return static_cast<u16char>(TChar<u8char>::ToLower(static_cast<u8char>(InChar))); return static_cast<u16char>(TChar<u8char>::ToLower(static_cast<u8char>(InChar)));
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::ToLower() only supports basic latin block.")); checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::ToLower() only supports basic latin block."));
@ -755,20 +762,20 @@ struct TChar
return static_cast<u16char>(TChar<u8char>::ToLower(static_cast<u8char>(InChar))); return static_cast<u16char>(TChar<u8char>::ToLower(static_cast<u8char>(InChar)));
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return InChar; return InChar;
} }
NODISCARD FORCEINLINE static constexpr CharType ToUpper(CharType InChar) NODISCARD FORCEINLINE static constexpr FCharType ToUpper(FCharType InChar)
{ {
if constexpr (CSameAs<CharType, char> || CSameAs<CharType, wchar>) if constexpr (CSameAs<FCharType, char> || CSameAs<FCharType, wchar>)
{ {
NAMESPACE_STD::locale Loc(""); NAMESPACE_STD::locale Loc("");
return static_cast<CharType>(NAMESPACE_STD::toupper(InChar, Loc)); return static_cast<FCharType>(NAMESPACE_STD::toupper(InChar, Loc));
} }
else if constexpr (CSameAs<CharType, u8char>) else if constexpr (CSameAs<FCharType, u8char>)
{ {
/* /*
* BASIC LATIN * BASIC LATIN
@ -785,7 +792,7 @@ struct TChar
return InChar; return InChar;
} }
else if constexpr (CSameAs<CharType, u16char>) else if constexpr (CSameAs<FCharType, u16char>)
{ {
checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::ToUpper() only supports basic latin block.")); checkf(InChar <= U16TEXT('\u007F'), TEXT("TChar::ToUpper() only supports basic latin block."));
@ -794,7 +801,7 @@ struct TChar
return static_cast<u16char>(TChar<u8char>::ToUpper(static_cast<u8char>(InChar))); return static_cast<u16char>(TChar<u8char>::ToUpper(static_cast<u8char>(InChar)));
} }
else if constexpr (CSameAs<CharType, u32char>) else if constexpr (CSameAs<FCharType, u32char>)
{ {
checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::ToUpper() only supports basic latin block.")); checkf(InChar <= U32TEXT('\u007F'), TEXT("TChar::ToUpper() only supports basic latin block."));
@ -803,12 +810,12 @@ struct TChar
return static_cast<u16char>(TChar<u8char>::ToUpper(static_cast<u8char>(InChar))); return static_cast<u16char>(TChar<u8char>::ToUpper(static_cast<u8char>(InChar)));
} }
else static_assert(sizeof(CharType) == -1, "Unsupported character type"); else static_assert(sizeof(FCharType) == -1, "Unsupported character type");
return InChar; return InChar;
} }
NODISCARD FORCEINLINE static constexpr unsigned ToDigit(CharType InChar) NODISCARD FORCEINLINE static constexpr unsigned ToDigit(FCharType InChar)
{ {
static_assert(TChar::IsASCII()); static_assert(TChar::IsASCII());
@ -834,12 +841,12 @@ struct TChar
static_assert(sizeof(DigitFromChar) == 256); static_assert(sizeof(DigitFromChar) == 256);
if constexpr (sizeof(CharType) > 1) if (InChar >> 8) return DigitFromChar[0]; if constexpr (sizeof(FCharType) > 1) if (InChar >> 8) return DigitFromChar[0];
return DigitFromChar[InChar]; return DigitFromChar[InChar];
} }
NODISCARD FORCEINLINE static constexpr unsigned ToDigit(CharType InChar, bool bLowercase) NODISCARD FORCEINLINE static constexpr unsigned ToDigit(FCharType InChar, bool bLowercase)
{ {
static_assert(TChar::IsASCII()); static_assert(TChar::IsASCII());
@ -867,7 +874,7 @@ struct TChar
static_assert(sizeof(DigitFromChar) == 256); static_assert(sizeof(DigitFromChar) == 256);
if constexpr (sizeof(CharType) > 1) if (InChar >> 8) return DigitFromChar[0]; if constexpr (sizeof(FCharType) > 1) if (InChar >> 8) return DigitFromChar[0];
return DigitFromChar[InChar]; return DigitFromChar[InChar];
} }
@ -894,25 +901,25 @@ struct TChar
static_assert(sizeof(DigitFromChar) == 256); static_assert(sizeof(DigitFromChar) == 256);
if constexpr (sizeof(CharType) > 1) if (InChar >> 8) return DigitFromChar[0]; if constexpr (sizeof(FCharType) > 1) if (InChar >> 8) return DigitFromChar[0];
return DigitFromChar[InChar]; return DigitFromChar[InChar];
} }
NODISCARD FORCEINLINE static constexpr CharType FromDigit(unsigned InDigit) NODISCARD FORCEINLINE static constexpr FCharType FromDigit(unsigned InDigit)
{ {
checkf(InDigit < 36, TEXT("Digit must be in the range [0, 35].")); checkf(InDigit < 36, TEXT("Digit must be in the range [0, 35]."));
return LITERAL(CharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit]; return LITERAL(FCharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit];
} }
NODISCARD FORCEINLINE static constexpr CharType FromDigit(unsigned InDigit, bool bLowercase) NODISCARD FORCEINLINE static constexpr FCharType FromDigit(unsigned InDigit, bool bLowercase)
{ {
checkf(InDigit < 36, TEXT("Digit must be in the range [0, 35].")); checkf(InDigit < 36, TEXT("Digit must be in the range [0, 35]."));
if (bLowercase) return LITERAL(CharType, "0123456789abcdefghijklmnopqrstuvwxyz")[InDigit]; if (bLowercase) return LITERAL(FCharType, "0123456789abcdefghijklmnopqrstuvwxyz")[InDigit];
return LITERAL(CharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit]; return LITERAL(FCharType, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")[InDigit];
} }
}; };

View 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)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -15,9 +15,9 @@ NAMESPACE_MODULE_BEGIN(Utility)
// NOTE: In the STL, the assignment operation of the std::any type uses the copy-and-swap idiom // NOTE: In the STL, the assignment operation of the std::any type uses the copy-and-swap idiom
// instead of directly calling the assignment operation of the contained value. // instead of directly calling the assignment operation of the contained value.
// The purpose of this is as follows: // The purpose of this is as follows:
// 1) the copy assignment might not exist. // 1) the copy assignment might not exist.
// 2) the typical case is that the objects are different. // 2) the typical case is that the objects are different.
// 3) it is less exception-safe // 3) it is less exception-safe
// But we don't follow the the copy-and-swap idiom, because we assume that no function throws an exception. // But we don't follow the the copy-and-swap idiom, because we assume that no function throws an exception.
@ -107,7 +107,7 @@ public:
{ {
EmplaceImpl<T>(Forward<Ts>(Args)...); EmplaceImpl<T>(Forward<Ts>(Args)...);
} }
/** Constructs an object with initial content an object of type TDecay<T>, direct-non-list-initialized from IL, Forward<Ts>(Args).... */ /** Constructs an object with initial content an object of type TDecay<T>, direct-non-list-initialized from IL, Forward<Ts>(Args).... */
template <typename T, typename U, typename... Ts> requires (NAMESPACE_PRIVATE::CFAnyPlaceable<T> && CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts&&...>) template <typename T, typename U, typename... Ts> requires (NAMESPACE_PRIVATE::CFAnyPlaceable<T> && CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts&&...>)
FORCEINLINE explicit FAny(TInPlaceType<T>, initializer_list<U> IL, Ts&&... Args) FORCEINLINE explicit FAny(TInPlaceType<T>, initializer_list<U> IL, Ts&&... Args)
@ -244,23 +244,23 @@ public:
&& NAMESPACE_PRIVATE::CFAnyPlaceable<T> && CConstructibleFrom<TDecay<T>, T&&>) && NAMESPACE_PRIVATE::CFAnyPlaceable<T> && CConstructibleFrom<TDecay<T>, T&&>)
FORCEINLINE FAny& operator=(T&& InValue) FORCEINLINE FAny& operator=(T&& InValue)
{ {
using DecayedType = TDecay<T>; using FDecayedType = TDecay<T>;
if constexpr (CAssignableFrom<DecayedType, T&&>) if constexpr (CAssignableFrom<FDecayedType, T&&>)
{ {
if (HoldsAlternative<DecayedType>()) if (HoldsAlternative<FDecayedType>())
{ {
GetValue<DecayedType>() = Forward<T>(InValue); GetValue<FDecayedType>() = Forward<T>(InValue);
return *this; return *this;
} }
} }
Destroy(); Destroy();
EmplaceImpl<DecayedType>(Forward<T>(InValue)); EmplaceImpl<FDecayedType>(Forward<T>(InValue));
return *this; return *this;
} }
/** Check if the contained value is equivalent to 'InValue'. */ /** Check if the contained value is equivalent to 'InValue'. */
template <typename T> requires (!CSameAs<FAny, TRemoveCVRef<T>> && NAMESPACE_PRIVATE::CFAnyPlaceable<T> && CEqualityComparable<T>) template <typename T> requires (!CSameAs<FAny, TRemoveCVRef<T>> && NAMESPACE_PRIVATE::CFAnyPlaceable<T> && CEqualityComparable<T>)
NODISCARD FORCEINLINE constexpr bool operator==(const T& InValue) const& NODISCARD FORCEINLINE constexpr bool operator==(const T& InValue) const&
@ -352,12 +352,12 @@ public:
Destroy(); Destroy();
Invalidate(); Invalidate();
} }
/** Overloads the Swap algorithm for FAny. */ /** Overloads the Swap algorithm for FAny. */
friend void Swap(FAny& A, FAny& B) friend void Swap(FAny& A, FAny& B)
{ {
if (!A.IsValid() && !B.IsValid()) return; if (!A.IsValid() && !B.IsValid()) return;
if (A.IsValid() && !B.IsValid()) if (A.IsValid() && !B.IsValid())
{ {
B = MoveTemp(A); B = MoveTemp(A);
@ -524,7 +524,7 @@ private:
default: check_no_entry(); return nullptr; default: check_no_entry(); return nullptr;
} }
} }
FORCEINLINE const void* GetStorage() const FORCEINLINE const void* GetStorage() const
{ {
switch (GetRepresentation()) switch (GetRepresentation())
@ -536,36 +536,36 @@ private:
default: check_no_entry(); return nullptr; default: check_no_entry(); return nullptr;
} }
} }
template <typename T, typename... Ts> template <typename T, typename... Ts>
void EmplaceImpl(Ts&&... Args) void EmplaceImpl(Ts&&... Args)
{ {
using DecayedType = TDecay<T>; using FDecayedType = TDecay<T>;
TypeInfo = reinterpret_cast<uintptr>(&typeid(DecayedType)); TypeInfo = reinterpret_cast<uintptr>(&typeid(FDecayedType));
if constexpr (CEmpty<DecayedType> && CTrivial<DecayedType>) return; // ERepresentation::Empty if constexpr (CEmpty<FDecayedType> && CTrivial<FDecayedType>) return; // ERepresentation::Empty
constexpr bool bIsTriviallyStorable = sizeof(DecayedType) <= sizeof(TrivialStorage.Internal) && alignof(DecayedType) <= alignof(FAny) && CTriviallyCopyable<DecayedType>; constexpr bool bIsTriviallyStorable = sizeof(FDecayedType) <= sizeof(TrivialStorage.Internal) && alignof(FDecayedType) <= alignof(FAny) && CTriviallyCopyable<FDecayedType>;
constexpr bool bIsSmallStorable = sizeof(DecayedType) <= sizeof( SmallStorage.Internal) && alignof(DecayedType) <= alignof(FAny); constexpr bool bIsSmallStorable = sizeof(FDecayedType) <= sizeof( SmallStorage.Internal) && alignof(FDecayedType) <= alignof(FAny);
static constexpr const FRTTI SelectedRTTI(InPlaceType<DecayedType>); static constexpr const FRTTI SelectedRTTI(InPlaceType<FDecayedType>);
if constexpr (bIsTriviallyStorable) if constexpr (bIsTriviallyStorable)
{ {
new (&TrivialStorage.Internal) DecayedType(Forward<Ts>(Args)...); new (&TrivialStorage.Internal) FDecayedType(Forward<Ts>(Args)...);
TypeInfo |= static_cast<uintptr>(ERepresentation::Trivial); TypeInfo |= static_cast<uintptr>(ERepresentation::Trivial);
} }
else if constexpr (bIsSmallStorable) else if constexpr (bIsSmallStorable)
{ {
new (&SmallStorage.Internal) DecayedType(Forward<Ts>(Args)...); new (&SmallStorage.Internal) FDecayedType(Forward<Ts>(Args)...);
SmallStorage.RTTI = &SelectedRTTI; SmallStorage.RTTI = &SelectedRTTI;
TypeInfo |= static_cast<uintptr>(ERepresentation::Small); TypeInfo |= static_cast<uintptr>(ERepresentation::Small);
} }
else else
{ {
BigStorage.External = Memory::Malloc(sizeof(DecayedType), alignof(DecayedType)); BigStorage.External = Memory::Malloc(sizeof(FDecayedType), alignof(FDecayedType));
new (BigStorage.External) DecayedType(Forward<Ts>(Args)...); new (BigStorage.External) FDecayedType(Forward<Ts>(Args)...);
BigStorage.RTTI = &SelectedRTTI; BigStorage.RTTI = &SelectedRTTI;
TypeInfo |= static_cast<uintptr>(ERepresentation::Big); TypeInfo |= static_cast<uintptr>(ERepresentation::Big);
} }

View File

@ -20,7 +20,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
* the values change in an order different from the order another thread wrote them. Indeed, * the values change in an order different from the order another thread wrote them. Indeed,
* the apparent order of changes can even differ among multiple reader threads. Some similar effects * the apparent order of changes can even differ among multiple reader threads. Some similar effects
* can occur even on uniprocessor systems due to compiler transformations allowed by the memory model. * can occur even on uniprocessor systems due to compiler transformations allowed by the memory model.
* *
* @see https://en.cppreference.com/w/cpp/atomic/memory_order * @see https://en.cppreference.com/w/cpp/atomic/memory_order
*/ */
enum class EMemoryOrder : uint8 enum class EMemoryOrder : uint8
@ -68,48 +68,48 @@ struct TAtomicImpl : FSingleton
{ {
protected: protected:
using NativeAtomicType = TConditional<bIsRef, NAMESPACE_STD::atomic_ref<T>, NAMESPACE_STD::atomic<T>>; using FNativeAtomic = TConditional<bIsRef, NAMESPACE_STD::atomic_ref<T>, NAMESPACE_STD::atomic<T>>;
public: public:
using ValueType = T; using FValueType = T;
/** Indicates that the type is always lock-free */ /** Indicates that the type is always lock-free */
static constexpr bool bIsAlwaysLockFree = NativeAtomicType::is_always_lock_free; static constexpr bool bIsAlwaysLockFree = FNativeAtomic::is_always_lock_free;
/** Indicates the required alignment of an object to be referenced by TAtomicRef. */ /** Indicates the required alignment of an object to be referenced by TAtomicRef. */
static constexpr size_t RequiredAlignment = NAMESPACE_STD::atomic_ref<T>::required_alignment; static constexpr size_t RequiredAlignment = NAMESPACE_STD::atomic_ref<T>::required_alignment;
/** Constructs an atomic object. */ /** Constructs an atomic object. */
FORCEINLINE constexpr TAtomicImpl() requires (!bIsRef) : NativeAtomic() { }; FORCEINLINE constexpr TAtomicImpl() requires (!bIsRef) : NativeAtomic() { }
FORCEINLINE constexpr TAtomicImpl(ValueType Desired) requires (!bIsRef) : NativeAtomic(Desired) { }; FORCEINLINE constexpr TAtomicImpl(FValueType Desired) requires (!bIsRef) : NativeAtomic(Desired) { }
/** Constructs an atomic reference. */ /** Constructs an atomic reference. */
FORCEINLINE explicit TAtomicImpl(ValueType& Desired) requires (bIsRef) : NativeAtomic(Desired) { check(Memory::IsAligned(&Desired, RequiredAlignment)); }; FORCEINLINE explicit TAtomicImpl(FValueType& Desired) requires (bIsRef) : NativeAtomic(Desired) { check(Memory::IsAligned(&Desired, RequiredAlignment)); }
FORCEINLINE TAtomicImpl(TAtomicImpl& InValue) requires (bIsRef) : NativeAtomic(InValue) { }; FORCEINLINE TAtomicImpl(TAtomicImpl& InValue) requires (bIsRef) : NativeAtomic(InValue) { }
/** Stores a value into an atomic object. */ /** Stores a value into an atomic object. */
FORCEINLINE ValueType operator=(ValueType Desired) { return NativeAtomic = Desired; } FORCEINLINE FValueType operator=(FValueType Desired) { return NativeAtomic = Desired; }
FORCEINLINE ValueType operator=(ValueType Desired) volatile requires (bIsAlwaysLockFree) { return NativeAtomic = Desired; } FORCEINLINE FValueType operator=(FValueType Desired) volatile requires (bIsAlwaysLockFree) { return NativeAtomic = Desired; }
/** Atomically replaces the value of the atomic object with a non-atomic argument. */ /** Atomically replaces the value of the atomic object with a non-atomic argument. */
FORCEINLINE void Store(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); NativeAtomic.store(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Store(FValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); NativeAtomic.store(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE void Store(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (bIsAlwaysLockFree) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); NativeAtomic.store(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Store(FValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (bIsAlwaysLockFree) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); NativeAtomic.store(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Atomically obtains the value of the atomic object. */ /** Atomically obtains the value of the atomic object. */
NODISCARD FORCEINLINE ValueType Load(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.load(static_cast<NAMESPACE_STD::memory_order>(Order)); } NODISCARD FORCEINLINE FValueType Load(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.load(static_cast<NAMESPACE_STD::memory_order>(Order)); }
NODISCARD FORCEINLINE ValueType Load(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile requires (bIsAlwaysLockFree) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.load(static_cast<NAMESPACE_STD::memory_order>(Order)); } NODISCARD FORCEINLINE FValueType Load(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile requires (bIsAlwaysLockFree) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.load(static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Loads a value from an atomic object. */ /** Loads a value from an atomic object. */
NODISCARD FORCEINLINE operator ValueType() const { return static_cast<ValueType>(NativeAtomic); } NODISCARD FORCEINLINE operator FValueType() const { return static_cast<FValueType>(NativeAtomic); }
NODISCARD FORCEINLINE operator ValueType() const volatile requires (bIsAlwaysLockFree) { return static_cast<ValueType>(NativeAtomic); } NODISCARD FORCEINLINE operator FValueType() const volatile requires (bIsAlwaysLockFree) { return static_cast<FValueType>(NativeAtomic); }
/** Atomically replaces the value of the atomic object and obtains the value held previously. */ /** Atomically replaces the value of the atomic object and obtains the value held previously. */
NODISCARD FORCEINLINE ValueType Exchange(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { return NativeAtomic.exchange(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); } NODISCARD FORCEINLINE FValueType Exchange(FValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { return NativeAtomic.exchange(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); }
NODISCARD FORCEINLINE ValueType Exchange(ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (bIsAlwaysLockFree) { return NativeAtomic.exchange(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); } NODISCARD FORCEINLINE FValueType Exchange(FValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (bIsAlwaysLockFree) { return NativeAtomic.exchange(Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not. */ /** Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not. */
NODISCARD FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Success, EMemoryOrder Failure, bool bIsWeak = false) NODISCARD FORCEINLINE bool CompareExchange(FValueType& Expected, FValueType Desired, EMemoryOrder Success, EMemoryOrder Failure, bool bIsWeak = false)
{ {
MEMORY_ORDER_CHECK(Failure, 0x01 | 0x02 | 0x04 | 0x20); MEMORY_ORDER_CHECK(Failure, 0x01 | 0x02 | 0x04 | 0x20);
if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure)); if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure));
@ -117,7 +117,7 @@ public:
} }
/** Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not. */ /** Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not. */
NODISCARD FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Success, EMemoryOrder Failure, bool bIsWeak = false) volatile requires (bIsAlwaysLockFree) NODISCARD FORCEINLINE bool CompareExchange(FValueType& Expected, FValueType Desired, EMemoryOrder Success, EMemoryOrder Failure, bool bIsWeak = false) volatile requires (bIsAlwaysLockFree)
{ {
MEMORY_ORDER_CHECK(Failure, 0x01 | 0x02 | 0x04 | 0x20); MEMORY_ORDER_CHECK(Failure, 0x01 | 0x02 | 0x04 | 0x20);
if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure)); if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Success), static_cast<NAMESPACE_STD::memory_order>(Failure));
@ -125,162 +125,162 @@ public:
} }
/** Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not. */ /** Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not. */
NODISCARD FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent, bool bIsWeak = false) NODISCARD FORCEINLINE bool CompareExchange(FValueType& Expected, FValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent, bool bIsWeak = false)
{ {
if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order));
else return NativeAtomic.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); else return NativeAtomic.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order));
} }
/** Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not. */ /** Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not. */
NODISCARD FORCEINLINE bool CompareExchange(ValueType& Expected, ValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent, bool bIsWeak = false) volatile requires (bIsAlwaysLockFree) NODISCARD FORCEINLINE bool CompareExchange(FValueType& Expected, FValueType Desired, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent, bool bIsWeak = false) volatile requires (bIsAlwaysLockFree)
{ {
if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); if (bIsWeak) return NativeAtomic.compare_exchange_weak(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order));
else return NativeAtomic.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order)); else return NativeAtomic.compare_exchange_strong(Expected, Desired, static_cast<NAMESPACE_STD::memory_order>(Order));
} }
/** Blocks the thread until notified and the atomic value changes. */ /** Blocks the thread until notified and the atomic value changes. */
FORCEINLINE void Wait(ValueType Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); NativeAtomic.wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Wait(FValueType Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); NativeAtomic.wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE void Wait(ValueType Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); NativeAtomic.wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Wait(FValueType Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); NativeAtomic.wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Notifies at least one or all threads blocked waiting on the atomic object. */ /** Notifies at least one or all threads blocked waiting on the atomic object. */
FORCEINLINE void Notify(bool bIsAll = false) { if (bIsAll) NativeAtomic.notify_all(); else NativeAtomic.notify_one(); } FORCEINLINE void Notify(bool bIsAll = false) { if (bIsAll) NativeAtomic.notify_all(); else NativeAtomic.notify_one(); }
FORCEINLINE void Notify(bool bIsAll = false) volatile { if (bIsAll) NativeAtomic.notify_all(); else NativeAtomic.notify_one(); } FORCEINLINE void Notify(bool bIsAll = false) volatile { if (bIsAll) NativeAtomic.notify_all(); else NativeAtomic.notify_one(); }
/** Atomically executes the 'Func' on the value stored in the atomic object and obtains the value held previously. */ /** Atomically executes the 'Func' on the value stored in the atomic object and obtains the value held previously. */
template <typename F> requires (CInvocableResult<ValueType, F, ValueType>) template <typename F> requires (CInvocableResult<FValueType, F, FValueType>)
FORCEINLINE ValueType FetchFn(F&& Func, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) FORCEINLINE FValueType FetchFn(F&& Func, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent)
{ {
ValueType Temp(Load(EMemoryOrder::Relaxed)); FValueType Temp(Load(EMemoryOrder::Relaxed));
// We do a weak read here because we require a loop. // We do a weak read here because we require a loop.
while (!CompareExchange(Temp, InvokeResult<ValueType>(Forward<F>(Func), Temp), Order, true)); while (!CompareExchange(Temp, InvokeResult<FValueType>(Forward<F>(Func), Temp), Order, true));
return Temp; return Temp;
} }
/** Atomically executes the 'Func' on the value stored in the atomic object and obtains the value held previously. */ /** Atomically executes the 'Func' on the value stored in the atomic object and obtains the value held previously. */
template <typename F> requires (CInvocableResult<ValueType, F, ValueType> && bIsAlwaysLockFree) template <typename F> requires (CInvocableResult<FValueType, F, FValueType> && bIsAlwaysLockFree)
FORCEINLINE ValueType FetchFn(F&& Func, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile FORCEINLINE FValueType FetchFn(F&& Func, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile
{ {
ValueType Temp(Load(EMemoryOrder::Relaxed)); FValueType Temp(Load(EMemoryOrder::Relaxed));
// We do a weak read here because we require a loop. // We do a weak read here because we require a loop.
while (!CompareExchange(Temp, InvokeResult<ValueType>(Forward<F>(Func), Temp), Order, true)); while (!CompareExchange(Temp, InvokeResult<FValueType>(Forward<F>(Func), Temp), Order, true));
return Temp; return Temp;
} }
/** Atomically adds the argument to the value stored in the atomic object and obtains the value held previously. */ /** Atomically adds the argument to the value stored in the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchAdd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchAdd(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchAdd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchAdd(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Atomically adds the argument to the value stored in the atomic object and obtains the value held previously. */ /** Atomically adds the argument to the value stored in the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchAdd(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CPointer<T> ) { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchAdd(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CPointer<T> ) { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchAdd(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchAdd(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_add(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Atomically subtracts the argument from the value stored in the atomic object and obtains the value held previously. */ /** Atomically subtracts the argument from the value stored in the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchSub(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchSub(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchSub(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchSub(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Atomically subtracts the argument from the value stored in the atomic object and obtains the value held previously. */ /** Atomically subtracts the argument from the value stored in the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchSub(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CPointer<T> ) { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchSub(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CPointer<T> ) { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchSub(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchSub(ptrdiff InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_sub(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Atomically multiples the argument from the value stored in the atomic object and obtains the value held previously. */ /** Atomically multiples the argument from the value stored in the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchMul(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old * InValue; }); } FORCEINLINE FValueType FetchMul(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return FetchFn([InValue](FValueType Old) -> FValueType { return Old * InValue; }); }
FORCEINLINE ValueType FetchMul(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return FetchFn([InValue](ValueType Old) -> ValueType { return Old * InValue; }); } FORCEINLINE FValueType FetchMul(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return FetchFn([InValue](FValueType Old) -> FValueType { return Old * InValue; }); }
/** Atomically divides the argument from the value stored in the atomic object and obtains the value held previously. */ /** Atomically divides the argument from the value stored in the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchDiv(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old / InValue; }); } FORCEINLINE FValueType FetchDiv(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> || CFloatingPoint<T>) { return FetchFn([InValue](FValueType Old) -> FValueType { return Old / InValue; }); }
FORCEINLINE ValueType FetchDiv(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return FetchFn([InValue](ValueType Old) -> ValueType { return Old / InValue; }); } FORCEINLINE FValueType FetchDiv(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree { return FetchFn([InValue](FValueType Old) -> FValueType { return Old / InValue; }); }
/** Atomically models the argument from the value stored in the atomic object and obtains the value held previously. */ /** Atomically models the argument from the value stored in the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchMod(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old % InValue; }); } FORCEINLINE FValueType FetchMod(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](FValueType Old) -> FValueType { return Old % InValue; }); }
FORCEINLINE ValueType FetchMod(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old % InValue; }); } FORCEINLINE FValueType FetchMod(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](FValueType Old) -> FValueType { return Old % InValue; }); }
/** Atomically performs bitwise AND between the argument and the value of the atomic object and obtains the value held previously. */ /** Atomically performs bitwise AND between the argument and the value of the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchAnd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return NativeAtomic.fetch_and(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchAnd(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return NativeAtomic.fetch_and(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchAnd(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_and(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchAnd(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_and(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Atomically performs bitwise OR between the argument and the value of the atomic object and obtains the value held previously. */ /** Atomically performs bitwise OR between the argument and the value of the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchOr(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return NativeAtomic.fetch_or(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchOr(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return NativeAtomic.fetch_or(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchOr(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_or(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchOr(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_or(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Atomically performs bitwise XOR between the argument and the value of the atomic object and obtains the value held previously. */ /** Atomically performs bitwise XOR between the argument and the value of the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchXor(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return NativeAtomic.fetch_xor(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchXor(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return NativeAtomic.fetch_xor(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE ValueType FetchXor(ValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_xor(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE FValueType FetchXor(FValueType InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic.fetch_xor(InValue, static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Atomically performs bitwise LSH between the argument and the value of the atomic object and obtains the value held previously. */ /** Atomically performs bitwise LSH between the argument and the value of the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchLsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old << InValue; }); } FORCEINLINE FValueType FetchLsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](FValueType Old) -> FValueType { return Old << InValue; }); }
FORCEINLINE ValueType FetchLsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old << InValue; }); } FORCEINLINE FValueType FetchLsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](FValueType Old) -> FValueType { return Old << InValue; }); }
/** Atomically performs bitwise RSH between the argument and the value of the atomic object and obtains the value held previously. */ /** Atomically performs bitwise RSH between the argument and the value of the atomic object and obtains the value held previously. */
FORCEINLINE ValueType FetchRsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old >> InValue; }); } FORCEINLINE FValueType FetchRsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) requires (CIntegral<T> ) { return FetchFn([InValue](FValueType Old) -> FValueType { return Old >> InValue; }); }
FORCEINLINE ValueType FetchRsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](ValueType Old) -> ValueType { return Old >> InValue; }); } FORCEINLINE FValueType FetchRsh(size_t InValue, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchFn([InValue](FValueType Old) -> FValueType { return Old >> InValue; }); }
/** Increments the atomic value by one. */
FORCEINLINE ValueType operator++() requires ((CIntegral<T> || CPointer<T>) ) { return ++NativeAtomic; }
FORCEINLINE ValueType operator++() volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return ++NativeAtomic; }
/** Increments the atomic value by one. */ /** Increments the atomic value by one. */
FORCEINLINE ValueType operator++(int) requires ((CIntegral<T> || CPointer<T>) ) { return NativeAtomic++; } FORCEINLINE FValueType operator++() requires ((CIntegral<T> || CPointer<T>) ) { return ++NativeAtomic; }
FORCEINLINE ValueType operator++(int) volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return NativeAtomic++; } FORCEINLINE FValueType operator++() volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return ++NativeAtomic; }
/** Increments the atomic value by one. */
FORCEINLINE FValueType operator++(int) requires ((CIntegral<T> || CPointer<T>) ) { return NativeAtomic++; }
FORCEINLINE FValueType operator++(int) volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return NativeAtomic++; }
/** Decrements the atomic value by one. */ /** Decrements the atomic value by one. */
FORCEINLINE ValueType operator--() requires ((CIntegral<T> || CPointer<T>) ) { return --NativeAtomic; } FORCEINLINE FValueType operator--() requires ((CIntegral<T> || CPointer<T>) ) { return --NativeAtomic; }
FORCEINLINE ValueType operator--() volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return --NativeAtomic; } FORCEINLINE FValueType operator--() volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return --NativeAtomic; }
/** Decrements the atomic value by one. */ /** Decrements the atomic value by one. */
FORCEINLINE ValueType operator--(int) requires ((CIntegral<T> || CPointer<T>) ) { return NativeAtomic--; } FORCEINLINE FValueType operator--(int) requires ((CIntegral<T> || CPointer<T>) ) { return NativeAtomic--; }
FORCEINLINE ValueType operator--(int) volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return NativeAtomic--; } FORCEINLINE FValueType operator--(int) volatile requires ((CIntegral<T> || CPointer<T>) && bIsAlwaysLockFree) { return NativeAtomic--; }
/** Adds with the atomic value. */
FORCEINLINE ValueType operator+=(ValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return NativeAtomic += InValue; }
FORCEINLINE ValueType operator+=(ValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return NativeAtomic += InValue; }
/** Adds with the atomic value. */ /** Adds with the atomic value. */
FORCEINLINE ValueType operator+=(ptrdiff InValue) requires (CPointer<T> ) { return NativeAtomic += InValue; } FORCEINLINE FValueType operator+=(FValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return NativeAtomic += InValue; }
FORCEINLINE ValueType operator+=(ptrdiff InValue) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic += InValue; } FORCEINLINE FValueType operator+=(FValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return NativeAtomic += InValue; }
/** Adds with the atomic value. */
FORCEINLINE FValueType operator+=(ptrdiff InValue) requires (CPointer<T> ) { return NativeAtomic += InValue; }
FORCEINLINE FValueType operator+=(ptrdiff InValue) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic += InValue; }
/** Subtracts with the atomic value. */ /** Subtracts with the atomic value. */
FORCEINLINE ValueType operator-=(ValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return NativeAtomic -= InValue; } FORCEINLINE FValueType operator-=(FValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return NativeAtomic -= InValue; }
FORCEINLINE ValueType operator-=(ValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return NativeAtomic -= InValue; } FORCEINLINE FValueType operator-=(FValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return NativeAtomic -= InValue; }
/** Subtracts with the atomic value. */ /** Subtracts with the atomic value. */
FORCEINLINE ValueType operator-=(ptrdiff InValue) requires (CPointer<T> ) { return NativeAtomic -= InValue; } FORCEINLINE FValueType operator-=(ptrdiff InValue) requires (CPointer<T> ) { return NativeAtomic -= InValue; }
FORCEINLINE ValueType operator-=(ptrdiff InValue) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic -= InValue; } FORCEINLINE FValueType operator-=(ptrdiff InValue) volatile requires (CPointer<T> && bIsAlwaysLockFree) { return NativeAtomic -= InValue; }
/** Multiples with the atomic value. */ /** Multiples with the atomic value. */
FORCEINLINE ValueType operator*=(ValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return FetchMul(InValue) * InValue; } FORCEINLINE FValueType operator*=(FValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return FetchMul(InValue) * InValue; }
FORCEINLINE ValueType operator*=(ValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return FetchMul(InValue) * InValue; } FORCEINLINE FValueType operator*=(FValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return FetchMul(InValue) * InValue; }
/** Divides with the atomic value. */ /** Divides with the atomic value. */
FORCEINLINE ValueType operator/=(ValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return FetchDiv(InValue) / InValue; } FORCEINLINE FValueType operator/=(FValueType InValue) requires ((CIntegral<T> || CFloatingPoint<T>) ) { return FetchDiv(InValue) / InValue; }
FORCEINLINE ValueType operator/=(ValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return FetchDiv(InValue) / InValue; } FORCEINLINE FValueType operator/=(FValueType InValue) volatile requires ((CIntegral<T> || CFloatingPoint<T>) && bIsAlwaysLockFree) { return FetchDiv(InValue) / InValue; }
/** Models with the atomic value. */ /** Models with the atomic value. */
FORCEINLINE ValueType operator%=(ValueType InValue) requires (CIntegral<T> ) { return FetchMod(InValue) % InValue; } FORCEINLINE FValueType operator%=(FValueType InValue) requires (CIntegral<T> ) { return FetchMod(InValue) % InValue; }
FORCEINLINE ValueType operator%=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchMod(InValue) % InValue; } FORCEINLINE FValueType operator%=(FValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchMod(InValue) % InValue; }
/** Performs bitwise AND with the atomic value. */ /** Performs bitwise AND with the atomic value. */
FORCEINLINE ValueType operator&=(ValueType InValue) requires (CIntegral<T> ) { return NativeAtomic &= InValue; } FORCEINLINE FValueType operator&=(FValueType InValue) requires (CIntegral<T> ) { return NativeAtomic &= InValue; }
FORCEINLINE ValueType operator&=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic &= InValue; } FORCEINLINE FValueType operator&=(FValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic &= InValue; }
/** Performs bitwise OR with the atomic value. */ /** Performs bitwise OR with the atomic value. */
FORCEINLINE ValueType operator|=(ValueType InValue) requires (CIntegral<T> ) { return NativeAtomic |= InValue; } FORCEINLINE FValueType operator|=(FValueType InValue) requires (CIntegral<T> ) { return NativeAtomic |= InValue; }
FORCEINLINE ValueType operator|=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic |= InValue; } FORCEINLINE FValueType operator|=(FValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic |= InValue; }
/** Performs bitwise XOR with the atomic value. */ /** Performs bitwise XOR with the atomic value. */
FORCEINLINE ValueType operator^=(ValueType InValue) requires (CIntegral<T> ) { return NativeAtomic ^= InValue; } FORCEINLINE FValueType operator^=(FValueType InValue) requires (CIntegral<T> ) { return NativeAtomic ^= InValue; }
FORCEINLINE ValueType operator^=(ValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic ^= InValue; } FORCEINLINE FValueType operator^=(FValueType InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return NativeAtomic ^= InValue; }
/** Performs bitwise LSH with the atomic value. */ /** Performs bitwise LSH with the atomic value. */
FORCEINLINE ValueType operator<<=(size_t InValue) requires (CIntegral<T> ) { return FetchLsh(InValue) << InValue; } FORCEINLINE FValueType operator<<=(size_t InValue) requires (CIntegral<T> ) { return FetchLsh(InValue) << InValue; }
FORCEINLINE ValueType operator<<=(size_t InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchLsh(InValue) << InValue; } FORCEINLINE FValueType operator<<=(size_t InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchLsh(InValue) << InValue; }
/** Performs bitwise RSH with the atomic value. */ /** Performs bitwise RSH with the atomic value. */
FORCEINLINE ValueType operator>>=(size_t InValue) requires (CIntegral<T> ) { return FetchRsh(InValue) >> InValue; } FORCEINLINE FValueType operator>>=(size_t InValue) requires (CIntegral<T> ) { return FetchRsh(InValue) >> InValue; }
FORCEINLINE ValueType operator>>=(size_t InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchRsh(InValue) >> InValue; } FORCEINLINE FValueType operator>>=(size_t InValue) volatile requires (CIntegral<T> && bIsAlwaysLockFree) { return FetchRsh(InValue) >> InValue; }
protected: protected:
NativeAtomicType NativeAtomic; FNativeAtomic NativeAtomic;
}; };
@ -311,7 +311,7 @@ struct FAtomicFlag final : FSingleton
public: public:
/** Constructs an atomic flag. */ /** Constructs an atomic flag. */
FORCEINLINE constexpr FAtomicFlag() : NativeAtomic() { }; FORCEINLINE constexpr FAtomicFlag() = default;
/** Atomically sets flag to false. */ /** Atomically sets flag to false. */
FORCEINLINE void Clear(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); NativeAtomic.clear(static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Clear(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) { MEMORY_ORDER_CHECK(Order, 0x01 | 0x08 | 0x20); NativeAtomic.clear(static_cast<NAMESPACE_STD::memory_order>(Order)); }
@ -324,7 +324,7 @@ public:
/** Atomically returns the value of the flag. */ /** Atomically returns the value of the flag. */
NODISCARD FORCEINLINE bool Test(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.test(static_cast<NAMESPACE_STD::memory_order>(Order)); } NODISCARD FORCEINLINE bool Test(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.test(static_cast<NAMESPACE_STD::memory_order>(Order)); }
NODISCARD FORCEINLINE bool Test(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.test(static_cast<NAMESPACE_STD::memory_order>(Order)); } NODISCARD FORCEINLINE bool Test(EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); return NativeAtomic.test(static_cast<NAMESPACE_STD::memory_order>(Order)); }
/** Blocks the thread until notified and the atomic value changes. */ /** Blocks the thread until notified and the atomic value changes. */
FORCEINLINE void Wait(bool Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); const_cast<const NAMESPACE_STD::atomic_flag&>(NativeAtomic).wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Wait(bool Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); const_cast<const NAMESPACE_STD::atomic_flag&>(NativeAtomic).wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); }
FORCEINLINE void Wait(bool Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); const_cast<const NAMESPACE_STD::atomic_flag&>(NativeAtomic).wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); } FORCEINLINE void Wait(bool Old, EMemoryOrder Order = EMemoryOrder::SequentiallyConsistent) const volatile { MEMORY_ORDER_CHECK(Order, 0x01 | 0x02 | 0x04 | 0x20); const_cast<const NAMESPACE_STD::atomic_flag&>(NativeAtomic).wait(Old, static_cast<NAMESPACE_STD::memory_order>(Order)); }
@ -332,7 +332,7 @@ public:
/** Notifies at least one or all threads blocked waiting on the atomic object. */ /** Notifies at least one or all threads blocked waiting on the atomic object. */
FORCEINLINE void Notify(bool bIsAll = false) { if (bIsAll) const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_all(); else const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_one(); } FORCEINLINE void Notify(bool bIsAll = false) { if (bIsAll) const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_all(); else const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_one(); }
FORCEINLINE void Notify(bool bIsAll = false) volatile { if (bIsAll) const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_all(); else const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_one(); } FORCEINLINE void Notify(bool bIsAll = false) volatile { if (bIsAll) const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_all(); else const_cast<NAMESPACE_STD::atomic_flag&>(NativeAtomic).notify_one(); }
private: private:
NAMESPACE_STD::atomic_flag NativeAtomic; NAMESPACE_STD::atomic_flag NativeAtomic;

View File

@ -262,29 +262,29 @@ public:
{ {
Callable = InCallable; Callable = InCallable;
using DecayedType = TDecay<T>; using FDecayedType = TDecay<T>;
static constexpr const FRTTI SelectedRTTI(InPlaceType<DecayedType>); static constexpr const FRTTI SelectedRTTI(InPlaceType<FDecayedType>);
RTTI = reinterpret_cast<uintptr>(&SelectedRTTI); RTTI = reinterpret_cast<uintptr>(&SelectedRTTI);
if constexpr (CEmpty<DecayedType> && CTrivial<DecayedType>) return; // ERepresentation::Empty if constexpr (CEmpty<FDecayedType> && CTrivial<FDecayedType>) return; // ERepresentation::Empty
constexpr bool bIsTriviallyStorable = sizeof(DecayedType) <= sizeof(InternalStorage) && alignof(DecayedType) <= alignof(TFunctionStorage) && CTriviallyCopyable<DecayedType>; constexpr bool bIsTriviallyStorable = sizeof(FDecayedType) <= sizeof(InternalStorage) && alignof(FDecayedType) <= alignof(TFunctionStorage) && CTriviallyCopyable<FDecayedType>;
constexpr bool bIsSmallStorable = sizeof(DecayedType) <= sizeof(InternalStorage) && alignof(DecayedType) <= alignof(TFunctionStorage); constexpr bool bIsSmallStorable = sizeof(FDecayedType) <= sizeof(InternalStorage) && alignof(FDecayedType) <= alignof(TFunctionStorage);
if constexpr (bIsTriviallyStorable) if constexpr (bIsTriviallyStorable)
{ {
new (&InternalStorage) DecayedType(Forward<Ts>(Args)...); new (&InternalStorage) FDecayedType(Forward<Ts>(Args)...);
RTTI |= static_cast<uintptr>(ERepresentation::Trivial); RTTI |= static_cast<uintptr>(ERepresentation::Trivial);
} }
else if constexpr (bIsSmallStorable) else if constexpr (bIsSmallStorable)
{ {
new (&InternalStorage) DecayedType(Forward<Ts>(Args)...); new (&InternalStorage) FDecayedType(Forward<Ts>(Args)...);
RTTI |= static_cast<uintptr>(ERepresentation::Small); RTTI |= static_cast<uintptr>(ERepresentation::Small);
} }
else else
{ {
ExternalStorage = new DecayedType(Forward<Ts>(Args)...); ExternalStorage = new FDecayedType(Forward<Ts>(Args)...);
RTTI |= static_cast<uintptr>(ERepresentation::Big); RTTI |= static_cast<uintptr>(ERepresentation::Big);
} }
@ -446,12 +446,12 @@ template <typename Ret, typename... Ts, typename F> struct TIsInvocableSignature
template <typename Ret, typename... Ts, typename F> struct TIsInvocableSignature<Ret(Ts...) const&&, F> : TBoolConstant<CInvocableResult<Ret, const F , Ts...>> { }; template <typename Ret, typename... Ts, typename F> struct TIsInvocableSignature<Ret(Ts...) const&&, F> : TBoolConstant<CInvocableResult<Ret, const F , Ts...>> { };
template <typename F> struct TFunctionInfo; template <typename F> struct TFunctionInfo;
template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) > { using Fn = Ret(Ts...); using CVRef = int; }; template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) > { using FFn = Ret(Ts...); using FCVRef = int; };
template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) & > { using Fn = Ret(Ts...); using CVRef = int&; }; template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) & > { using FFn = Ret(Ts...); using FCVRef = int&; };
template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) && > { using Fn = Ret(Ts...); using CVRef = int&&; }; template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) && > { using FFn = Ret(Ts...); using FCVRef = int&&; };
template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) const > { using Fn = Ret(Ts...); using CVRef = const int; }; template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) const > { using FFn = Ret(Ts...); using FCVRef = const int; };
template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) const& > { using Fn = Ret(Ts...); using CVRef = const int&; }; template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) const& > { using FFn = Ret(Ts...); using FCVRef = const int&; };
template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) const&&> { using Fn = Ret(Ts...); using CVRef = const int&&; }; template <typename Ret, typename... Ts> struct TFunctionInfo<Ret(Ts...) const&&> { using FFn = Ret(Ts...); using FCVRef = const int&&; };
template <typename F, typename CVRef, bool bIsRef, bool bIsUnique = false> class TFunctionImpl; template <typename F, typename CVRef, bool bIsRef, bool bIsUnique = false> class TFunctionImpl;
@ -460,8 +460,8 @@ class TFunctionImpl<Ret(Ts...), CVRef, bIsRef, bIsUnique>
{ {
public: public:
using ResultType = Ret; using FResultType = Ret;
using ArgumentType = TTypeSequence<Ts...>; using FArgumentType = TTypeSequence<Ts...>;
FORCEINLINE constexpr TFunctionImpl() = default; FORCEINLINE constexpr TFunctionImpl() = default;
FORCEINLINE constexpr TFunctionImpl(const TFunctionImpl&) = default; FORCEINLINE constexpr TFunctionImpl(const TFunctionImpl&) = default;
@ -471,12 +471,12 @@ public:
FORCEINLINE constexpr ~TFunctionImpl() = default; FORCEINLINE constexpr ~TFunctionImpl() = default;
/** Invokes the stored callable function target with the parameters args. */ /** Invokes the stored callable function target with the parameters args. */
FORCEINLINE ResultType operator()(Ts... Args) requires (CSameAs<CVRef, int >) { return CallImpl(Forward<Ts>(Args)...); } FORCEINLINE FResultType operator()(Ts... Args) requires (CSameAs<CVRef, int >) { return CallImpl(Forward<Ts>(Args)...); }
FORCEINLINE ResultType operator()(Ts... Args) & requires (CSameAs<CVRef, int& >) { return CallImpl(Forward<Ts>(Args)...); } FORCEINLINE FResultType operator()(Ts... Args) & requires (CSameAs<CVRef, int& >) { return CallImpl(Forward<Ts>(Args)...); }
FORCEINLINE ResultType operator()(Ts... Args) && requires (CSameAs<CVRef, int&&>) { return CallImpl(Forward<Ts>(Args)...); } FORCEINLINE FResultType operator()(Ts... Args) && requires (CSameAs<CVRef, int&&>) { return CallImpl(Forward<Ts>(Args)...); }
FORCEINLINE ResultType operator()(Ts... Args) const requires (CSameAs<CVRef, const int >) { return CallImpl(Forward<Ts>(Args)...); } FORCEINLINE FResultType operator()(Ts... Args) const requires (CSameAs<CVRef, const int >) { return CallImpl(Forward<Ts>(Args)...); }
FORCEINLINE ResultType operator()(Ts... Args) const& requires (CSameAs<CVRef, const int& >) { return CallImpl(Forward<Ts>(Args)...); } FORCEINLINE FResultType operator()(Ts... Args) const& requires (CSameAs<CVRef, const int& >) { return CallImpl(Forward<Ts>(Args)...); }
FORCEINLINE ResultType operator()(Ts... Args) const&& requires (CSameAs<CVRef, const int&&>) { return CallImpl(Forward<Ts>(Args)...); } FORCEINLINE FResultType operator()(Ts... Args) const&& requires (CSameAs<CVRef, const int&&>) { return CallImpl(Forward<Ts>(Args)...); }
/** @return false if instance stores a callable function target, true otherwise. */ /** @return false if instance stores a callable function target, true otherwise. */
NODISCARD FORCEINLINE constexpr bool operator==(nullptr_t) const& requires (!bIsRef) { return !IsValid(); } NODISCARD FORCEINLINE constexpr bool operator==(nullptr_t) const& requires (!bIsRef) { return !IsValid(); }
@ -487,14 +487,14 @@ public:
private: private:
using CallableType = ResultType(*)(uintptr, Ts&&...); using FCallableType = FResultType(*)(uintptr, Ts&&...);
TFunctionStorage<bIsRef, bIsUnique> Storage; TFunctionStorage<bIsRef, bIsUnique> Storage;
FORCEINLINE ResultType CallImpl(Ts&&... Args) const FORCEINLINE FResultType CallImpl(Ts&&... Args) const
{ {
checkf(Storage.IsValid(), TEXT("Attempting to call an unbound TFunction!")); checkf(Storage.IsValid(), TEXT("Attempting to call an unbound TFunction!"));
CallableType Callable = reinterpret_cast<CallableType>(Storage.GetCallable()); FCallableType Callable = reinterpret_cast<FCallableType>(Storage.GetCallable());
return Callable(Storage.GetValuePtr(), Forward<Ts>(Args)...); return Callable(Storage.GetValuePtr(), Forward<Ts>(Args)...);
} }
@ -510,26 +510,26 @@ protected:
template <typename T, typename... Us> template <typename T, typename... Us>
FORCEINLINE constexpr TDecay<T>& Emplace(Us&&... Args) FORCEINLINE constexpr TDecay<T>& Emplace(Us&&... Args)
{ {
using DecayedType = TDecay<T>; using FDecayedType = TDecay<T>;
// This add a l-value reference to a non-reference type, while preserving the r-value reference. // This add a l-value reference to a non-reference type, while preserving the r-value reference.
using ObjectType = TCopyCVRef<CVRef, DecayedType>; using FObjectType = TCopyCVRef<CVRef, FDecayedType>;
using InvokeType = TConditional<CReference<ObjectType>, ObjectType, ObjectType&>; using FInvokeType = TConditional<CReference<FObjectType>, FObjectType, FObjectType&>;
CallableType Callable = [](uintptr ObjectPtr, Ts&&... Args) -> ResultType FCallableType Callable = [](uintptr ObjectPtr, Ts&&... Args) -> FResultType
{ {
return InvokeResult<ResultType>( return InvokeResult<FResultType>(
static_cast<InvokeType>(*reinterpret_cast<DecayedType*>(ObjectPtr)), static_cast<FInvokeType>(*reinterpret_cast<FDecayedType*>(ObjectPtr)),
Forward<Ts>(Args)... Forward<Ts>(Args)...
); );
}; };
Storage.template Emplace<DecayedType>( Storage.template Emplace<FDecayedType>(
reinterpret_cast<uintptr>(Callable), reinterpret_cast<uintptr>(Callable),
Forward<Us>(Args)... Forward<Us>(Args)...
); );
return *reinterpret_cast<DecayedType*>(Storage.GetValuePtr()); return *reinterpret_cast<FDecayedType*>(Storage.GetValuePtr());
} }
friend FORCEINLINE constexpr void Swap(TFunctionImpl& A, TFunctionImpl& B) requires (!bIsRef) { Swap(A.Storage, B.Storage); } friend FORCEINLINE constexpr void Swap(TFunctionImpl& A, TFunctionImpl& B) requires (!bIsRef) { Swap(A.Storage, B.Storage); }
@ -552,15 +552,15 @@ NAMESPACE_PRIVATE_END
template <CFunction F> template <CFunction F>
class TFunctionRef final class TFunctionRef final
: public NAMESPACE_PRIVATE::TFunctionImpl< : public NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FFn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FCVRef,
true> true>
{ {
private: private:
using Impl = NAMESPACE_PRIVATE::TFunctionImpl< using FImpl = NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FFn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FCVRef,
true>; true>;
public: public:
@ -585,7 +585,7 @@ public:
FORCEINLINE constexpr TFunctionRef(T&& InValue) FORCEINLINE constexpr TFunctionRef(T&& InValue)
{ {
checkf(NAMESPACE_PRIVATE::FunctionIsBound(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef")); checkf(NAMESPACE_PRIVATE::FunctionIsBound(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef"));
Impl::template Emplace<T>(Forward<T>(InValue)); FImpl::template Emplace<T>(Forward<T>(InValue));
} }
template <typename T> template <typename T>
@ -602,21 +602,21 @@ public:
template <CFunction F> template <CFunction F>
class TFunction final class TFunction final
: public NAMESPACE_PRIVATE::TFunctionImpl< : public NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FFn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FCVRef,
false, false> false, false>
{ {
private: private:
using Impl = NAMESPACE_PRIVATE::TFunctionImpl< using FImpl = NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FFn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FCVRef,
false, false>; false, false>;
public: public:
/** Default constructor. */ /** Default constructor. */
FORCEINLINE constexpr TFunction(nullptr_t = nullptr) { Impl::Invalidate(); } FORCEINLINE constexpr TFunction(nullptr_t = nullptr) { FImpl::Invalidate(); }
FORCEINLINE TFunction(const TFunction&) = default; FORCEINLINE TFunction(const TFunction&) = default;
FORCEINLINE TFunction(TFunction&&) = default; FORCEINLINE TFunction(TFunction&&) = default;
@ -634,8 +634,8 @@ public:
&& NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value) && NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value)
FORCEINLINE TFunction(T&& InValue) FORCEINLINE TFunction(T&& InValue)
{ {
if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Impl::Invalidate(); if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) FImpl::Invalidate();
else Impl::template Emplace<T>(Forward<T>(InValue)); else FImpl::template Emplace<T>(Forward<T>(InValue));
} }
/** /**
@ -647,7 +647,7 @@ public:
&& CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>) && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE explicit TFunction(TInPlaceType<T>, Ts&&... Args) FORCEINLINE explicit TFunction(TInPlaceType<T>, Ts&&... Args)
{ {
Impl::template Emplace<T>(Forward<Ts>(Args)...); FImpl::template Emplace<T>(Forward<Ts>(Args)...);
} }
/** /**
@ -659,7 +659,7 @@ public:
&& CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>) && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE explicit TFunction(TInPlaceType<T>, initializer_list<U> IL, Ts&&... Args) FORCEINLINE explicit TFunction(TInPlaceType<T>, initializer_list<U> IL, Ts&&... Args)
{ {
Impl::template Emplace<T>(IL, Forward<Ts>(Args)...); FImpl::template Emplace<T>(IL, Forward<Ts>(Args)...);
} }
/** Removes any bound callable from the TFunction, restoring it to the default empty state. */ /** Removes any bound callable from the TFunction, restoring it to the default empty state. */
@ -692,8 +692,8 @@ public:
&& CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>) && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE TDecay<T>& Emplace(Ts&&... Args) FORCEINLINE TDecay<T>& Emplace(Ts&&... Args)
{ {
Impl::Destroy(); FImpl::Destroy();
return Impl::template Emplace<T>(Forward<Ts>(Args)...); return FImpl::template Emplace<T>(Forward<Ts>(Args)...);
} }
/** /**
@ -710,15 +710,15 @@ public:
&& CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>) && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE TDecay<T>& Emplace(initializer_list<U> IL, Ts&&... Args) FORCEINLINE TDecay<T>& Emplace(initializer_list<U> IL, Ts&&... Args)
{ {
Impl::Destroy(); FImpl::Destroy();
return Impl::template Emplace<T>(IL, Forward<Ts>(Args)...); return FImpl::template Emplace<T>(IL, Forward<Ts>(Args)...);
} }
/** Removes any bound callable from the TFunction, restoring it to the default empty state. */ /** Removes any bound callable from the TFunction, restoring it to the default empty state. */
FORCEINLINE constexpr void Reset() { Impl::Destroy(); Impl::Invalidate(); } FORCEINLINE constexpr void Reset() { FImpl::Destroy(); FImpl::Invalidate(); }
/** Overloads the Swap algorithm for TFunction. */ /** Overloads the Swap algorithm for TFunction. */
friend FORCEINLINE constexpr void Swap(TFunction& A, TFunction& B) { Swap(static_cast<Impl&>(A), static_cast<Impl&>(B)); } friend FORCEINLINE constexpr void Swap(TFunction& A, TFunction& B) { Swap(static_cast<FImpl&>(A), static_cast<FImpl&>(B)); }
}; };
@ -731,21 +731,21 @@ public:
template <CFunction F> template <CFunction F>
class TUniqueFunction final class TUniqueFunction final
: public NAMESPACE_PRIVATE::TFunctionImpl< : public NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FFn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FCVRef,
false, true> false, true>
{ {
private: private:
using Impl = NAMESPACE_PRIVATE::TFunctionImpl< using FImpl = NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FFn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef, typename NAMESPACE_PRIVATE::TFunctionInfo<F>::FCVRef,
false, true>; false, true>;
public: public:
/** Default constructor. */ /** Default constructor. */
FORCEINLINE constexpr TUniqueFunction(nullptr_t = nullptr) { Impl::Invalidate(); } FORCEINLINE constexpr TUniqueFunction(nullptr_t = nullptr) { FImpl::Invalidate(); }
FORCEINLINE TUniqueFunction(const TUniqueFunction&) = delete; FORCEINLINE TUniqueFunction(const TUniqueFunction&) = delete;
FORCEINLINE TUniqueFunction(TUniqueFunction&&) = default; FORCEINLINE TUniqueFunction(TUniqueFunction&&) = default;
@ -788,8 +788,8 @@ public:
&& NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value) && NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value)
FORCEINLINE TUniqueFunction(T&& InValue) FORCEINLINE TUniqueFunction(T&& InValue)
{ {
if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Impl::Invalidate(); if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) FImpl::Invalidate();
else Impl::template Emplace<T>(Forward<T>(InValue)); else FImpl::template Emplace<T>(Forward<T>(InValue));
} }
/** /**
@ -800,7 +800,7 @@ public:
&& CConstructibleFrom<TDecay<T>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>) && CConstructibleFrom<TDecay<T>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE explicit TUniqueFunction(TInPlaceType<T>, Ts&&... Args) FORCEINLINE explicit TUniqueFunction(TInPlaceType<T>, Ts&&... Args)
{ {
Impl::template Emplace<T>(Forward<Ts>(Args)...); FImpl::template Emplace<T>(Forward<Ts>(Args)...);
} }
/** /**
@ -811,11 +811,11 @@ public:
&& CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>) && CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE explicit TUniqueFunction(TInPlaceType<T>, initializer_list<U> IL, Ts&&... Args) FORCEINLINE explicit TUniqueFunction(TInPlaceType<T>, initializer_list<U> IL, Ts&&... Args)
{ {
Impl::template Emplace<T>(IL, Forward<Ts>(Args)...); FImpl::template Emplace<T>(IL, Forward<Ts>(Args)...);
} }
/** Removes any bound callable from the TUniqueFunction, restoring it to the default empty state. */ /** Removes any bound callable from the TUniqueFunction, restoring it to the default empty state. */
FORCEINLINE constexpr TUniqueFunction& operator=(nullptr_t) { Impl::Destroy(); Impl::Invalidate(); return *this; } FORCEINLINE constexpr TUniqueFunction& operator=(nullptr_t) { FImpl::Destroy(); FImpl::Invalidate(); return *this; }
template <typename T> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value template <typename T> requires (NAMESPACE_PRIVATE::TIsInvocableSignature<F, TDecay<T>>::Value
&& !CTFunctionRef<TDecay<T>> && !CTFunction<TDecay<T>> && !CTUniqueFunction<TDecay<T>> && !CTFunctionRef<TDecay<T>> && !CTFunction<TDecay<T>> && !CTUniqueFunction<TDecay<T>>
@ -841,9 +841,9 @@ public:
&& CConstructibleFrom<TDecay<T>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>) && CConstructibleFrom<TDecay<T>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE TDecay<T>& Emplace(Ts&&... Args) FORCEINLINE TDecay<T>& Emplace(Ts&&... Args)
{ {
Impl::Destroy(); FImpl::Destroy();
using DecayedType = TDecay<T>;
return Impl::template Emplace<T>(Forward<Ts>(Args)...); return FImpl::template Emplace<T>(Forward<Ts>(Args)...);
} }
/** /**
@ -859,16 +859,16 @@ public:
&& CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>) && CConstructibleFrom<TDecay<T>, initializer_list<U>, Ts...> && CMoveConstructible<TDecay<T>> && CDestructible<TDecay<T>>)
FORCEINLINE TDecay<T>& Emplace(initializer_list<U> IL, Ts&&... Args) FORCEINLINE TDecay<T>& Emplace(initializer_list<U> IL, Ts&&... Args)
{ {
Impl::Destroy(); FImpl::Destroy();
using DecayedType = TDecay<T>;
return Impl::template Emplace<T>(IL, Forward<Ts>(Args)...); return FImpl::template Emplace<T>(IL, Forward<Ts>(Args)...);
} }
/** Removes any bound callable from the TUniqueFunction, restoring it to the default empty state. */ /** Removes any bound callable from the TUniqueFunction, restoring it to the default empty state. */
FORCEINLINE constexpr void Reset() { Impl::Destroy(); Impl::Invalidate(); } FORCEINLINE constexpr void Reset() { FImpl::Destroy(); FImpl::Invalidate(); }
/** Overloads the Swap algorithm for TUniqueFunction. */ /** Overloads the Swap algorithm for TUniqueFunction. */
friend FORCEINLINE constexpr void Swap(TUniqueFunction& A, TUniqueFunction& B) { Swap(static_cast<Impl&>(A), static_cast<Impl&>(B)); } friend FORCEINLINE constexpr void Swap(TUniqueFunction& A, TUniqueFunction& B) { Swap(static_cast<FImpl&>(A), static_cast<FImpl&>(B)); }
}; };

View File

@ -10,7 +10,7 @@ NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_PRIVATE_BEGIN NAMESPACE_PRIVATE_BEGIN
struct InvokeFunction struct FInvokeFunction
{ {
template <typename F, typename... Ts> template <typename F, typename... Ts>
static auto Invoke(F&& Object, Ts&&... Args) static auto Invoke(F&& Object, Ts&&... Args)
@ -20,7 +20,7 @@ struct InvokeFunction
} }
}; };
struct InvokeMemberFunction struct FInvokeMemberFunction
{ {
template <typename F, typename ObjectType, typename... Ts> template <typename F, typename ObjectType, typename... Ts>
static auto Invoke(F&& Func, ObjectType&& Object, Ts&&... Args) static auto Invoke(F&& Func, ObjectType&& Object, Ts&&... Args)
@ -37,7 +37,7 @@ struct InvokeMemberFunction
} }
}; };
struct InvokeMemberObject struct FInvokeMemberObject
{ {
template <typename F, typename ObjectType> template <typename F, typename ObjectType>
static auto Invoke(F&& Func, ObjectType&& Object) static auto Invoke(F&& Func, ObjectType&& Object)
@ -59,34 +59,34 @@ template <typename F,
typename Decayed = TDecay<F>, typename Decayed = TDecay<F>,
bool IsMemberFunction = CMemberFunctionPointer<Decayed>, bool IsMemberFunction = CMemberFunctionPointer<Decayed>,
bool IsMemberObject = CMemberObjectPointer<Decayed>> bool IsMemberObject = CMemberObjectPointer<Decayed>>
struct InvokeMember; struct FInvokeMember;
template <typename F, typename T, typename Decayed> template <typename F, typename T, typename Decayed>
struct InvokeMember<F, T, Decayed, true, false> : InvokeMemberFunction { }; struct FInvokeMember<F, T, Decayed, true, false> : FInvokeMemberFunction { };
template <typename F, typename T, typename Decayed> template <typename F, typename T, typename Decayed>
struct InvokeMember<F, T, Decayed, false, true> : InvokeMemberObject { }; struct FInvokeMember<F, T, Decayed, false, true> : FInvokeMemberObject { };
template <typename F, typename T, typename Decayed> template <typename F, typename T, typename Decayed>
struct InvokeMember<F, T, Decayed, false, false> : InvokeFunction { }; struct FInvokeMember<F, T, Decayed, false, false> : FInvokeFunction { };
template <typename F, typename... Ts> template <typename F, typename... Ts>
struct InvokeImpl; struct FInvokeImpl;
template <typename F> template <typename F>
struct InvokeImpl<F> : InvokeFunction { }; struct FInvokeImpl<F> : FInvokeFunction { };
template <typename F, typename T, typename... Ts> template <typename F, typename T, typename... Ts>
struct InvokeImpl<F, T, Ts...> : InvokeMember<F, T> { }; struct FInvokeImpl<F, T, Ts...> : FInvokeMember<F, T> { };
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
/** Invoke the Callable object f with the parameters args. */ /** Invoke the Callable object f with the parameters args. */
template <typename F, typename... Ts> requires (CInvocable<F, Ts...>) template <typename F, typename... Ts> requires (CInvocable<F, Ts...>)
FORCEINLINE constexpr auto Invoke(F&& Func, Ts&&... Args) FORCEINLINE constexpr auto Invoke(F&& Func, Ts&&... Args)
-> decltype(NAMESPACE_PRIVATE::InvokeImpl<F, Ts...>::Invoke(Forward<F>(Func), Forward<Ts>(Args)...)) -> decltype(NAMESPACE_PRIVATE::FInvokeImpl<F, Ts...>::Invoke(Forward<F>(Func), Forward<Ts>(Args)...))
{ {
return NAMESPACE_PRIVATE::InvokeImpl<F, Ts...>::Invoke(Forward<F>(Func), Forward<Ts>(Args)...); return NAMESPACE_PRIVATE::FInvokeImpl<F, Ts...>::Invoke(Forward<F>(Func), Forward<Ts>(Args)...);
} }
/** Invoke the Callable object f with the parameters args. */ /** Invoke the Callable object f with the parameters args. */

View File

@ -3,7 +3,6 @@
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
#include "TypeTraits/TypeTraits.h" #include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/Container.h"
NAMESPACE_REDCRAFT_BEGIN NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Redcraft)
@ -12,9 +11,8 @@ NAMESPACE_MODULE_BEGIN(Utility)
template <typename T, T... Ints> template <typename T, T... Ints>
struct TIntegerSequence struct TIntegerSequence
{ {
using ValueType = T; using FValueType = T;
FORCEINLINE static constexpr size_t Num() { return sizeof...(Ints); } FORCEINLINE static constexpr size_t Num() { return sizeof...(Ints); }
FORCEINLINE static constexpr const T* GetData() { return NAMESPACE_REDCRAFT::GetData({ Ints... }); }
}; };
NAMESPACE_PRIVATE_BEGIN NAMESPACE_PRIVATE_BEGIN
@ -24,7 +22,7 @@ NAMESPACE_PRIVATE_BEGIN
template <unsigned N, typename T> template <unsigned N, typename T>
struct TMakeIntegerSequenceImpl struct TMakeIntegerSequenceImpl
{ {
using Type = typename __make_integer_seq<TIntegerSequence, T, N>; using FType = typename __make_integer_seq<TIntegerSequence, T, N>;
}; };
#elif __has_builtin(__make_integer_seq) #elif __has_builtin(__make_integer_seq)
@ -32,7 +30,7 @@ struct TMakeIntegerSequenceImpl
template <unsigned N, typename T> template <unsigned N, typename T>
struct TMakeIntegerSequenceImpl struct TMakeIntegerSequenceImpl
{ {
using Type = typename __make_integer_seq<TIntegerSequence, T, N>; using FType = typename __make_integer_seq<TIntegerSequence, T, N>;
}; };
#else #else
@ -40,13 +38,13 @@ struct TMakeIntegerSequenceImpl
template <unsigned N, typename T, T... Ints> template <unsigned N, typename T, T... Ints>
struct TMakeIntegerSequenceImpl struct TMakeIntegerSequenceImpl
{ {
using Type = typename TMakeIntegerSequenceImpl<N - 1, T, T(N - 1), Ints...>::Type; using FType = typename TMakeIntegerSequenceImpl<N - 1, T, T(N - 1), Ints...>::FType;
}; };
template <typename T, T... Ints> template <typename T, T... Ints>
struct TMakeIntegerSequenceImpl<0, T, Ints...> struct TMakeIntegerSequenceImpl<0, T, Ints...>
{ {
using Type = TIntegerSequence<T, Ints...>; using FType = TIntegerSequence<T, Ints...>;
}; };
#endif #endif
@ -57,7 +55,7 @@ template <size_t... Ints>
using TIndexSequence = TIntegerSequence<size_t, Ints...>; using TIndexSequence = TIntegerSequence<size_t, Ints...>;
template <typename T, T N> template <typename T, T N>
using TMakeIntegerSequence = typename NAMESPACE_PRIVATE::TMakeIntegerSequenceImpl<N, T>::Type; using TMakeIntegerSequence = typename NAMESPACE_PRIVATE::TMakeIntegerSequenceImpl<N, T>::FType;
template <size_t N> template <size_t N>
using TMakeIndexSequence = TMakeIntegerSequence<size_t, N>; using TMakeIndexSequence = TMakeIntegerSequence<size_t, N>;
@ -103,7 +101,7 @@ struct TFrontImpl;
template <typename T, typename... Ts> template <typename T, typename... Ts>
struct TFrontImpl<TTypeSequence<T, Ts...>> struct TFrontImpl<TTypeSequence<T, Ts...>>
{ {
using Type = T; using FType = T;
}; };
template <typename TSequence> template <typename TSequence>
@ -112,7 +110,7 @@ struct TPopImpl;
template <typename T, typename... Ts> template <typename T, typename... Ts>
struct TPopImpl<TTypeSequence<T, Ts...>> struct TPopImpl<TTypeSequence<T, Ts...>>
{ {
using Type = TTypeSequence<Ts...>; using FType = TTypeSequence<Ts...>;
}; };
template <typename T, typename TSequence> template <typename T, typename TSequence>
@ -121,19 +119,19 @@ struct TPushImpl;
template <typename T, typename... Ts> template <typename T, typename... Ts>
struct TPushImpl<T, TTypeSequence<Ts...>> struct TPushImpl<T, TTypeSequence<Ts...>>
{ {
using Type = TTypeSequence<T, Ts...>; using FType = TTypeSequence<T, Ts...>;
}; };
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
template <CTTypeSequence TSequence> template <CTTypeSequence TSequence>
using TFront = typename NAMESPACE_PRIVATE::TFrontImpl<TSequence>::Type; using TFront = typename NAMESPACE_PRIVATE::TFrontImpl<TSequence>::FType;
template <CTTypeSequence TSequence> template <CTTypeSequence TSequence>
using TPop = typename NAMESPACE_PRIVATE::TPopImpl<TSequence>::Type; using TPop = typename NAMESPACE_PRIVATE::TPopImpl<TSequence>::FType;
template <typename T, typename TSequence> template <typename T, typename TSequence>
using TPush = typename NAMESPACE_PRIVATE::TPushImpl<T, TSequence>::Type; using TPush = typename NAMESPACE_PRIVATE::TPushImpl<T, TSequence>::FType;
NAMESPACE_PRIVATE_BEGIN NAMESPACE_PRIVATE_BEGIN
@ -194,19 +192,19 @@ struct TIndexAssert
template <size_t I, typename TSequence> template <size_t I, typename TSequence>
struct TTypeImpl struct TTypeImpl
{ {
using Type = typename TTypeImpl<I - 1, TPop<TSequence>>::Type; using FType = typename TTypeImpl<I - 1, TPop<TSequence>>::FType;
}; };
template <typename TSequence> template <typename TSequence>
struct TTypeImpl<0, TSequence> struct TTypeImpl<0, TSequence>
{ {
using Type = TFront<TSequence>; using FType = TFront<TSequence>;
}; };
template <typename TSequence> template <typename TSequence>
struct TTypeImpl<INDEX_NONE, TSequence> struct TTypeImpl<INDEX_NONE, TSequence>
{ {
using Type = void; using FType = void;
}; };
template <size_t I, typename TSequence> template <size_t I, typename TSequence>
@ -214,7 +212,7 @@ struct TTypeAssert
{ {
static_assert(I < TSizeImpl<TSequence>::Value, "I is invalid index in type sequence"); static_assert(I < TSizeImpl<TSequence>::Value, "I is invalid index in type sequence");
static constexpr size_t SafeIndex = I < TSizeImpl<TSequence>::Value ? I : INDEX_NONE; static constexpr size_t SafeIndex = I < TSizeImpl<TSequence>::Value ? I : INDEX_NONE;
using Type = TCopyCV<TSequence, typename TTypeImpl<SafeIndex, TSequence>::Type>; using FType = TCopyCV<TSequence, typename TTypeImpl<SafeIndex, TSequence>::FType>;
}; };
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
@ -226,29 +224,29 @@ template <typename T, CTTypeSequence TSequence>
inline constexpr size_t TIndex = NAMESPACE_PRIVATE::TIndexAssert<T, TSequence>::Value; inline constexpr size_t TIndex = NAMESPACE_PRIVATE::TIndexAssert<T, TSequence>::Value;
template <size_t I, CTTypeSequence TSequence> template <size_t I, CTTypeSequence TSequence>
using TType = typename NAMESPACE_PRIVATE::TTypeAssert<I, TSequence>::Type; using TType = typename NAMESPACE_PRIVATE::TTypeAssert<I, TSequence>::FType;
NAMESPACE_PRIVATE_BEGIN NAMESPACE_PRIVATE_BEGIN
template <typename TSequence> template <typename TSequence>
struct TUniqueTypeSequenceImpl struct TUniqueTypeSequenceImpl
{ {
using FrontType = TFront<TSequence>; using FFrontType = TFront<TSequence>;
using NextSequence = TPop<TSequence>; using FNextSequence = TPop<TSequence>;
using NextUniqueSequence = typename TUniqueTypeSequenceImpl<NextSequence>::Type; using FNextUniqueSequence = typename TUniqueTypeSequenceImpl<FNextSequence>::FType;
using Type = TConditional<!CExistentType<FrontType, NextSequence>, TPush<FrontType, NextUniqueSequence>, NextUniqueSequence>; using FType = TConditional<!CExistentType<FFrontType, FNextSequence>, TPush<FFrontType, FNextUniqueSequence>, FNextUniqueSequence>;
}; };
template <> template <>
struct TUniqueTypeSequenceImpl<TTypeSequence<>> struct TUniqueTypeSequenceImpl<TTypeSequence<>>
{ {
using Type = TTypeSequence<>; using FType = TTypeSequence<>;
}; };
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
template <CTTypeSequence TSequence> template <CTTypeSequence TSequence>
using TUniqueTypeSequence = typename NAMESPACE_PRIVATE::TUniqueTypeSequenceImpl<TSequence>::Type; using TUniqueTypeSequence = typename NAMESPACE_PRIVATE::TUniqueTypeSequenceImpl<TSequence>::FType;
NAMESPACE_PRIVATE_BEGIN NAMESPACE_PRIVATE_BEGIN

View File

@ -45,9 +45,9 @@ class TOptional<T, false> final
{ {
public: public:
using ValueType = T; using FValueType = T;
static_assert(!CReference<ValueType>); static_assert(!CReference<FValueType>);
/** Constructs an object that does not contain a value. */ /** Constructs an object that does not contain a value. */
FORCEINLINE constexpr TOptional() : bIsValid(false) { } FORCEINLINE constexpr TOptional() : bIsValid(false) { }
@ -56,8 +56,8 @@ public:
FORCEINLINE constexpr TOptional(FInvalid) : TOptional() { } FORCEINLINE constexpr TOptional(FInvalid) : TOptional() { }
/** Constructs an object with initial content an object, direct-initialized from Forward<U>(InValue). */ /** Constructs an object with initial content an object, direct-initialized from Forward<U>(InValue). */
template <typename U = T> requires (CConstructibleFrom<T, U&&>) template <typename U = T> requires (CConstructibleFrom<T, U&&>
&& (!CSameAs<TRemoveCVRef<U>, FInPlace>) && (!CSameAs<TOptional, TRemoveCVRef<U>>) && !CSameAs<TRemoveCVRef<U>, FInPlace> && !CSameAs<TOptional, TRemoveCVRef<U>>)
FORCEINLINE constexpr explicit (!CConvertibleTo<U&&, T>) TOptional(U&& InValue) FORCEINLINE constexpr explicit (!CConvertibleTo<U&&, T>) TOptional(U&& InValue)
: TOptional(InPlace, Forward<U>(InValue)) : TOptional(InPlace, Forward<U>(InValue))
{ } { }
@ -67,7 +67,7 @@ public:
FORCEINLINE constexpr explicit TOptional(FInPlace, Ts&&... Args) FORCEINLINE constexpr explicit TOptional(FInPlace, Ts&&... Args)
: bIsValid(true) : bIsValid(true)
{ {
new (&Value) ValueType(Forward<Ts>(Args)...); new (&Value) FValueType(Forward<Ts>(Args)...);
} }
/** Constructs an object with initial content an object, direct-non-list-initialized from IL, Forward<Ts>(Args).... */ /** Constructs an object with initial content an object, direct-non-list-initialized from IL, Forward<Ts>(Args).... */
@ -75,7 +75,7 @@ public:
FORCEINLINE constexpr explicit TOptional(FInPlace, initializer_list<W> IL, Ts&&... Args) FORCEINLINE constexpr explicit TOptional(FInPlace, initializer_list<W> IL, Ts&&... Args)
: bIsValid(true) : bIsValid(true)
{ {
new (&Value) ValueType(IL, Forward<Ts>(Args)...); new (&Value) FValueType(IL, Forward<Ts>(Args)...);
} }
/** Copies content of other into a new instance. */ /** Copies content of other into a new instance. */
@ -85,7 +85,7 @@ public:
FORCEINLINE constexpr TOptional(const TOptional& InValue) requires (CCopyConstructible<T> && !CTriviallyCopyConstructible<T>) FORCEINLINE constexpr TOptional(const TOptional& InValue) requires (CCopyConstructible<T> && !CTriviallyCopyConstructible<T>)
: bIsValid(InValue.IsValid()) : bIsValid(InValue.IsValid())
{ {
if (InValue.IsValid()) new (&Value) ValueType(InValue.GetValue()); if (InValue.IsValid()) new (&Value) FValueType(InValue.GetValue());
} }
/** Moves content of other into a new instance. */ /** Moves content of other into a new instance. */
@ -95,7 +95,7 @@ public:
FORCEINLINE constexpr TOptional(TOptional&& InValue) requires (CMoveConstructible<T> && !CTriviallyMoveConstructible<T>) FORCEINLINE constexpr TOptional(TOptional&& InValue) requires (CMoveConstructible<T> && !CTriviallyMoveConstructible<T>)
: bIsValid(InValue.IsValid()) : bIsValid(InValue.IsValid())
{ {
if (InValue.IsValid()) new (&Value) ValueType(MoveTemp(InValue.GetValue())); if (InValue.IsValid()) new (&Value) FValueType(MoveTemp(InValue.GetValue()));
} }
/** Converting copy constructor. */ /** Converting copy constructor. */
@ -103,7 +103,7 @@ public:
FORCEINLINE constexpr explicit (!CConvertibleTo<const U&, T>) TOptional(const TOptional<U>& InValue) FORCEINLINE constexpr explicit (!CConvertibleTo<const U&, T>) TOptional(const TOptional<U>& InValue)
: bIsValid(InValue.IsValid()) : bIsValid(InValue.IsValid())
{ {
if (InValue.IsValid()) new (&Value) ValueType(InValue.GetValue()); if (InValue.IsValid()) new (&Value) FValueType(InValue.GetValue());
} }
/** Converting move constructor. */ /** Converting move constructor. */
@ -111,7 +111,7 @@ public:
FORCEINLINE constexpr explicit (!CConvertibleTo<U&&, T>) TOptional(TOptional<U>&& InValue) FORCEINLINE constexpr explicit (!CConvertibleTo<U&&, T>) TOptional(TOptional<U>&& InValue)
: bIsValid(InValue.IsValid()) : bIsValid(InValue.IsValid())
{ {
if (InValue.IsValid()) new (&Value) ValueType(MoveTemp(InValue.GetValue())); if (InValue.IsValid()) new (&Value) FValueType(MoveTemp(InValue.GetValue()));
} }
/** Destroys the contained object, if any, as if by a call to Reset(). */ /** Destroys the contained object, if any, as if by a call to Reset(). */
@ -141,7 +141,7 @@ public:
if (IsValid()) GetValue() = InValue.GetValue(); if (IsValid()) GetValue() = InValue.GetValue();
else else
{ {
new (&Value) ValueType(InValue.GetValue()); new (&Value) FValueType(InValue.GetValue());
bIsValid = true; bIsValid = true;
} }
@ -166,7 +166,7 @@ public:
if (IsValid()) GetValue() = MoveTemp(InValue.GetValue()); if (IsValid()) GetValue() = MoveTemp(InValue.GetValue());
else else
{ {
new (&Value) ValueType(MoveTemp(InValue.GetValue())); new (&Value) FValueType(MoveTemp(InValue.GetValue()));
bIsValid = true; bIsValid = true;
} }
@ -187,7 +187,7 @@ public:
if (IsValid()) GetValue() = InValue.GetValue(); if (IsValid()) GetValue() = InValue.GetValue();
else else
{ {
new (&Value) ValueType(InValue.GetValue()); new (&Value) FValueType(InValue.GetValue());
bIsValid = true; bIsValid = true;
} }
@ -208,7 +208,7 @@ public:
if (IsValid()) GetValue() = MoveTemp(InValue.GetValue()); if (IsValid()) GetValue() = MoveTemp(InValue.GetValue());
else else
{ {
new (&Value) ValueType(MoveTemp(InValue.GetValue())); new (&Value) FValueType(MoveTemp(InValue.GetValue()));
bIsValid = true; bIsValid = true;
} }
@ -222,7 +222,7 @@ public:
if (IsValid()) GetValue() = Forward<U>(InValue); if (IsValid()) GetValue() = Forward<U>(InValue);
else else
{ {
new (&Value) ValueType(Forward<U>(InValue)); new (&Value) FValueType(Forward<U>(InValue));
bIsValid = true; bIsValid = true;
} }
@ -278,7 +278,7 @@ public:
{ {
Reset(); Reset();
T* Result = new (&Value) ValueType(Forward<Ts>(Args)...); T* Result = new (&Value) FValueType(Forward<Ts>(Args)...);
bIsValid = true; bIsValid = true;
return *Result; return *Result;
@ -298,7 +298,7 @@ public:
{ {
Reset(); Reset();
T* Result = new (&Value) ValueType(IL, Forward<Ts>(Args)...); T* Result = new (&Value) FValueType(IL, Forward<Ts>(Args)...);
bIsValid = true; bIsValid = true;
return *Result; return *Result;
@ -335,7 +335,7 @@ public:
{ {
bIsValid = false; bIsValid = false;
reinterpret_cast<T*>(&Value)->~ValueType(); reinterpret_cast<T*>(&Value)->~FValueType();
} }
} }
@ -380,9 +380,9 @@ class TOptional<T, true> final
{ {
public: public:
using ValueType = TRemoveReference<T>; using FValueType = TRemoveReference<T>;
static_assert(!CReference<ValueType>); static_assert(!CReference<FValueType>);
/** Constructs an object that does not contain a reference. */ /** Constructs an object that does not contain a reference. */
FORCEINLINE constexpr TOptional() : Ptr(nullptr) { } FORCEINLINE constexpr TOptional() : Ptr(nullptr) { }
@ -408,13 +408,13 @@ public:
{ } { }
/** Converting constructor. */ /** Converting constructor. */
template <typename U> requires (!CConst<ValueType> && CConstructibleFrom<T, U&> && NAMESPACE_PRIVATE::CTOptionalAllowUnwrappable<U, T>) template <typename U> requires (!CConst<FValueType> && CConstructibleFrom<T, U&> && NAMESPACE_PRIVATE::CTOptionalAllowUnwrappable<U, T>)
FORCEINLINE constexpr explicit (!CConvertibleTo<U&, T>) TOptional(TOptional<U, false>& InValue) FORCEINLINE constexpr explicit (!CConvertibleTo<U&, T>) TOptional(TOptional<U, false>& InValue)
: Ptr(InValue.IsValid() ? AddressOf(static_cast<T>(InValue.GetValue())) : nullptr) : Ptr(InValue.IsValid() ? AddressOf(static_cast<T>(InValue.GetValue())) : nullptr)
{ } { }
/** Converting constructor. */ /** Converting constructor. */
template <typename U> requires (CConst<ValueType> && CConstructibleFrom<T, const U&> && NAMESPACE_PRIVATE::CTOptionalAllowUnwrappable<U, T>) template <typename U> requires (CConst<FValueType> && CConstructibleFrom<T, const U&> && NAMESPACE_PRIVATE::CTOptionalAllowUnwrappable<U, T>)
FORCEINLINE constexpr explicit (!CConvertibleTo<const U&, T>) TOptional(const TOptional<U, false>& InValue) FORCEINLINE constexpr explicit (!CConvertibleTo<const U&, T>) TOptional(const TOptional<U, false>& InValue)
: Ptr(InValue.IsValid() ? AddressOf(static_cast<T>(InValue.GetValue())) : nullptr) : Ptr(InValue.IsValid() ? AddressOf(static_cast<T>(InValue.GetValue())) : nullptr)
{ } { }
@ -492,7 +492,7 @@ public:
private: private:
ValueType* Ptr; FValueType* Ptr;
}; };

View File

@ -24,7 +24,7 @@ template <typename T>
concept CTPropagateConst = NAMESPACE_PRIVATE::TIsTPropagateConst<TRemoveCV<T>>::Value; concept CTPropagateConst = NAMESPACE_PRIVATE::TIsTPropagateConst<TRemoveCV<T>>::Value;
/** /**
* TPropagateConst is a const-propagating wrapper for pointers and pointer-like objects. * TPropagateConst is a const-propagating wrapper for pointers and pointer-like objects.
* It treats the wrapped pointer as a pointer to const when accessed through a const access path, hence the name. * It treats the wrapped pointer as a pointer to const when accessed through a const access path, hence the name.
*/ */
template <typename T> requires (TPointerTraits<T>::bIsPointer) template <typename T> requires (TPointerTraits<T>::bIsPointer)
@ -32,7 +32,7 @@ class TPropagateConst final
{ {
public: public:
using ElementType = TPointerTraits<T>::ElementType; using FElementType = TPointerTraits<T>::FElementType;
/** Constructs an TPropagateConst, default-initializing underlying pointer. */ /** Constructs an TPropagateConst, default-initializing underlying pointer. */
FORCEINLINE constexpr TPropagateConst() = default; FORCEINLINE constexpr TPropagateConst() = default;
@ -105,26 +105,26 @@ public:
NODISCARD FORCEINLINE constexpr decltype(auto) operator<=>(U InPtr) const& { return SynthThreeWayCompare(Ptr, InPtr); } NODISCARD FORCEINLINE constexpr decltype(auto) operator<=>(U InPtr) const& { return SynthThreeWayCompare(Ptr, InPtr); }
/** @return The pointer to the object pointed to by the wrapped pointer. */ /** @return The pointer to the object pointed to by the wrapped pointer. */
NODISCARD FORCEINLINE constexpr ElementType* Get() { return TPointerTraits<T>::ToAddress(Ptr); } NODISCARD FORCEINLINE constexpr FElementType* Get() { return TPointerTraits<T>::ToAddress(Ptr); }
NODISCARD FORCEINLINE constexpr const ElementType* Get() const { return TPointerTraits<T>::ToAddress(Ptr); } NODISCARD FORCEINLINE constexpr const FElementType* Get() const { return TPointerTraits<T>::ToAddress(Ptr); }
/** @return true if *this owns an object, false otherwise. */ /** @return true if *this owns an object, false otherwise. */
NODISCARD FORCEINLINE constexpr bool IsValid() const { return Get() != nullptr; } NODISCARD FORCEINLINE constexpr bool IsValid() const { return Get() != nullptr; }
NODISCARD FORCEINLINE constexpr explicit operator bool() const { return Get() != nullptr; } NODISCARD FORCEINLINE constexpr explicit operator bool() const { return Get() != nullptr; }
/** @return The a reference or pointer to the object owned by *this, i.e. Get(). */ /** @return The a reference or pointer to the object owned by *this, i.e. Get(). */
NODISCARD FORCEINLINE constexpr ElementType& operator*() { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return *Get(); } NODISCARD FORCEINLINE constexpr FElementType& operator*() { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return *Get(); }
NODISCARD FORCEINLINE constexpr const ElementType& operator*() const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return *Get(); } NODISCARD FORCEINLINE constexpr const FElementType& operator*() const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return *Get(); }
NODISCARD FORCEINLINE constexpr ElementType* operator->() { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get(); } NODISCARD FORCEINLINE constexpr FElementType* operator->() { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get(); }
NODISCARD FORCEINLINE constexpr const ElementType* operator->() const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get(); } NODISCARD FORCEINLINE constexpr const FElementType* operator->() const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get(); }
/** @return The element at index, i.e. Get()[Index]. */ /** @return The element at index, i.e. Get()[Index]. */
NODISCARD FORCEINLINE constexpr T& operator[](size_t Index) { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get()[Index]; } NODISCARD FORCEINLINE constexpr T& operator[](size_t Index) { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get()[Index]; }
NODISCARD FORCEINLINE constexpr const T& operator[](size_t Index) const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get()[Index]; } NODISCARD FORCEINLINE constexpr const T& operator[](size_t Index) const { checkf(IsValid(), TEXT("Read access violation. Please check IsValid().")); return Get()[Index]; }
/** @return The pointer to the object pointed to by the wrapped pointer-like object. */ /** @return The pointer to the object pointed to by the wrapped pointer-like object. */
NODISCARD FORCEINLINE constexpr operator ElementType*() requires (CConvertibleTo<T, ElementType*>) { return Ptr; } NODISCARD FORCEINLINE constexpr operator FElementType*() requires (CConvertibleTo<T, FElementType*>) { return Ptr; }
NODISCARD FORCEINLINE constexpr operator const ElementType*() const requires (CConvertibleTo<T, ElementType*>) { return Ptr; } NODISCARD FORCEINLINE constexpr operator const FElementType*() const requires (CConvertibleTo<T, FElementType*>) { return Ptr; }
/** @return The reference to the pointer-like object stored. */ /** @return The reference to the pointer-like object stored. */
NODISCARD FORCEINLINE constexpr T& GetUnderlying() { return Ptr; } NODISCARD FORCEINLINE constexpr T& GetUnderlying() { return Ptr; }

View File

@ -22,7 +22,7 @@ class TReferenceWrapper final
{ {
public: public:
using Type = ReferencedType; using FType = ReferencedType;
/** Constructs a new reference wrapper. */ /** Constructs a new reference wrapper. */
template <typename T = ReferencedType&> requires (CConvertibleTo<T&&, ReferencedType&> && !CSameAs<TReferenceWrapper, TRemoveCVRef<T>>) template <typename T = ReferencedType&> requires (CConvertibleTo<T&&, ReferencedType&> && !CSameAs<TReferenceWrapper, TRemoveCVRef<T>>)
@ -94,27 +94,15 @@ FORCEINLINE constexpr TReferenceWrapper<T> Ref(TReferenceWrapper<T> InValue)
return Ref(InValue.Get()); 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 NAMESPACE_PRIVATE_BEGIN
template <typename T> struct TIsTReferenceWrapperImpl : FFalse { }; template <typename T> struct TIsTReferenceWrapperImpl : FFalse { };
template <typename T> struct TIsTReferenceWrapperImpl<TReferenceWrapper<T>> : FTrue { }; template <typename T> struct TIsTReferenceWrapperImpl<TReferenceWrapper<T>> : FTrue { };
template <typename T> struct TUnwrapReferenceImpl { using Type = T; }; template <typename T> struct TUnwrapReferenceImpl { using FType = T; };
template <typename T> struct TUnwrapReferenceImpl<TReferenceWrapper<T>> { using Type = T&; }; template <typename T> struct TUnwrapReferenceImpl<TReferenceWrapper<T>> { using FType = T&; };
template <typename T> struct TUnwrapRefDecayImpl { using Type = typename TUnwrapReferenceImpl<TDecay<T>>::Type; }; template <typename T> struct TUnwrapRefDecayImpl { using FType = typename TUnwrapReferenceImpl<TDecay<T>>::FType; };
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
@ -122,10 +110,10 @@ template <typename T>
concept CTReferenceWrapper = NAMESPACE_PRIVATE::TIsTReferenceWrapperImpl<TRemoveCV<T>>::Value; concept CTReferenceWrapper = NAMESPACE_PRIVATE::TIsTReferenceWrapperImpl<TRemoveCV<T>>::Value;
template <typename T> template <typename T>
using TUnwrapReference = typename NAMESPACE_PRIVATE::TUnwrapReferenceImpl<T>::Type; using TUnwrapReference = typename NAMESPACE_PRIVATE::TUnwrapReferenceImpl<T>::FType;
template <typename T> template <typename T>
using TUnwrapRefDecay = typename NAMESPACE_PRIVATE::TUnwrapRefDecayImpl<T>::Type; using TUnwrapRefDecay = typename NAMESPACE_PRIVATE::TUnwrapRefDecayImpl<T>::FType;
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)

View File

@ -49,7 +49,7 @@ struct TTupleElementImpl;
template <size_t I, typename... Ts> template <size_t I, typename... Ts>
struct TTupleElementImpl<I, TTuple<Ts...>> struct TTupleElementImpl<I, TTuple<Ts...>>
{ {
using Type = Meta::TType<I, TTypeSequence<Ts...>>; using FType = Meta::TType<I, TTypeSequence<Ts...>>;
}; };
template <bool bTrue, typename... Ts> template <bool bTrue, typename... Ts>
@ -77,12 +77,12 @@ struct TTupleBasicElement
{ {
private: private:
using ValueType = T; using FValueType = T;
ValueType Value; FValueType Value;
public: public:
template <typename Type> template <typename Type> requires (CConstructibleFrom<T, Type&&>)
FORCEINLINE constexpr TTupleBasicElement(Type&& Arg) FORCEINLINE constexpr TTupleBasicElement(Type&& Arg)
: Value(Forward<Type>(Arg)) : Value(Forward<Type>(Arg))
{ } { }
@ -110,10 +110,10 @@ public:
template <typename T> \ template <typename T> \
struct TTupleBasicElement<T, Index> \ struct TTupleBasicElement<T, Index> \
{ \ { \
using Name##Type = T; \ using F##Name##Type = T; \
Name##Type Name; \ F##Name##Type Name; \
\ \
template <typename Type> \ template <typename Type> requires (CConstructibleFrom<T, F##Name##Type&&>) \
FORCEINLINE constexpr TTupleBasicElement(Type&& Arg) \ FORCEINLINE constexpr TTupleBasicElement(Type&& Arg) \
: Name(Forward<Type>(Arg)) \ : Name(Forward<Type>(Arg)) \
{ } \ { } \
@ -278,28 +278,37 @@ struct TTTupleSynthThreeWayComparable<TTypeSequence<>, TTypeSequence<>> : FTrue
template <typename TSequence, typename USequence> template <typename TSequence, typename USequence>
concept CTTupleSynthThreeWayComparable = TTTupleSynthThreeWayComparable<TSequence, USequence>::Value; concept CTTupleSynthThreeWayComparable = TTTupleSynthThreeWayComparable<TSequence, USequence>::Value;
template <typename Ret, typename Indices> template <typename Ret, typename F, typename TTupleType>
struct TTupleVisitElementByIndex; struct TTupleVisitElementByIndex
template <typename Ret, size_t I, size_t... Indices>
struct TTupleVisitElementByIndex<Ret, TIndexSequence<I, Indices...>>
{ {
template <typename F, typename TTupleType> template <size_t Index>
FORCEINLINE static constexpr decltype(auto) Do(F&& Func, TTupleType&& Arg, size_t Index) struct TInvokeElement
{ {
if (Index == I) return InvokeResult<Ret>(Forward<F>(Func), Forward<TTupleType>(Arg).template GetValue<I>()); FORCEINLINE static constexpr Ret Do(F&& Func, TTupleType&& Arg)
return TTupleVisitElementByIndex<Ret, TIndexSequence<Indices...>>::Do(Forward<F>(Func), Forward<TTupleType>(Arg), Index); {
} return InvokeResult<Ret>(Forward<F>(Func), Forward<TTupleType>(Arg).template GetValue<Index>());
}; }
};
template <typename Ret> template <typename>
struct TTupleVisitElementByIndex<Ret, TIndexSequence<>> struct TInvokeTuple;
{
template <typename F, typename TTupleType> template <size_t... Indices>
FORCEINLINE static constexpr decltype(auto) Do(F&& Func, TTupleType&& Arg, size_t) struct TInvokeTuple<TIndexSequence<Indices...>>
{ {
checkf(false, "Read access violation. Please check Index."); FORCEINLINE static constexpr Ret Do(F&& Func, TTupleType&& Arg, size_t Index)
return InvokeResult<Ret>(Forward<F>(Func), Forward<TTupleType>(Arg).template GetValue<0>()); {
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);
} }
}; };
@ -315,15 +324,15 @@ template <typename T, CTTuple U>
inline constexpr size_t TTupleIndex = NAMESPACE_PRIVATE::TTupleIndexImpl<T, TRemoveCV<U>>::Value; inline constexpr size_t TTupleIndex = NAMESPACE_PRIVATE::TTupleIndexImpl<T, TRemoveCV<U>>::Value;
template <size_t I, CTTuple U> template <size_t I, CTTuple U>
using TTupleElement = TCopyCV<U, typename NAMESPACE_PRIVATE::TTupleElementImpl<I, TRemoveCV<U>>::Type>; using TTupleElement = TCopyCV<U, typename NAMESPACE_PRIVATE::TTupleElementImpl<I, TRemoveCV<U>>::FType>;
template <typename... Ts> template <typename... Ts>
class TTuple final : public NAMESPACE_PRIVATE::TTupleImpl<TIndexSequenceFor<Ts...>, Ts...> class TTuple final : public NAMESPACE_PRIVATE::TTupleImpl<TIndexSequenceFor<Ts...>, Ts...>
{ {
private: private:
using Super = NAMESPACE_PRIVATE::TTupleImpl<TIndexSequenceFor<Ts...>, Ts...>; using FSuper = NAMESPACE_PRIVATE::TTupleImpl<TIndexSequenceFor<Ts...>, Ts...>;
using Helper = NAMESPACE_PRIVATE::TTupleHelper<TIndexSequenceFor<Ts...>>; using FHelper = NAMESPACE_PRIVATE::TTupleHelper<TIndexSequenceFor<Ts...>>;
public: public:
@ -334,7 +343,7 @@ public:
template <typename... Us> requires (sizeof...(Ts) >= 1 && sizeof...(Us) == sizeof...(Ts)) template <typename... Us> requires (sizeof...(Ts) >= 1 && sizeof...(Us) == sizeof...(Ts))
&& (true && ... && CConstructibleFrom<Ts, Us&&>) && (true && ... && CConstructibleFrom<Ts, Us&&>)
FORCEINLINE constexpr explicit (!(true && ... && CConvertibleTo<Us&&, Ts>)) TTuple(Us&&... Args) FORCEINLINE constexpr explicit (!(true && ... && CConvertibleTo<Us&&, Ts>)) TTuple(Us&&... Args)
: Super(NAMESPACE_PRIVATE::ForwardingConstructor, Forward<Us>(Args)...) : FSuper(NAMESPACE_PRIVATE::ForwardingConstructor, Forward<Us>(Args)...)
{ } { }
/** Converting copy constructor. Initializes each element of the tuple with the corresponding element of other. */ /** Converting copy constructor. Initializes each element of the tuple with the corresponding element of other. */
@ -342,7 +351,7 @@ public:
&& (true && ... && CConstructibleFrom<Ts, const Us&>) && (true && ... && CConstructibleFrom<Ts, const Us&>)
&& NAMESPACE_PRIVATE::TTupleConvertCopy<sizeof...(Ts) != 1, Ts..., Us...>::Value) && NAMESPACE_PRIVATE::TTupleConvertCopy<sizeof...(Ts) != 1, Ts..., Us...>::Value)
FORCEINLINE constexpr explicit (!(true && ... && CConvertibleTo<Us&&, Ts>)) TTuple(const TTuple<Us...>& InValue) FORCEINLINE constexpr explicit (!(true && ... && CConvertibleTo<Us&&, Ts>)) TTuple(const TTuple<Us...>& InValue)
: Super(NAMESPACE_PRIVATE::OtherTupleConstructor, InValue) : FSuper(NAMESPACE_PRIVATE::OtherTupleConstructor, InValue)
{ } { }
/** Converting move constructor. Initializes each element of the tuple with the corresponding element of other. */ /** Converting move constructor. Initializes each element of the tuple with the corresponding element of other. */
@ -350,7 +359,7 @@ public:
&& (true && ... && CConstructibleFrom<Ts, Us&&>) && (true && ... && CConstructibleFrom<Ts, Us&&>)
&& NAMESPACE_PRIVATE::TTupleConvertMove<sizeof...(Ts) != 1, Ts..., Us...>::Value) && NAMESPACE_PRIVATE::TTupleConvertMove<sizeof...(Ts) != 1, Ts..., Us...>::Value)
FORCEINLINE constexpr explicit (!(true && ... && CConvertibleTo<Us&&, Ts>)) TTuple(TTuple<Us...>&& InValue) FORCEINLINE constexpr explicit (!(true && ... && CConvertibleTo<Us&&, Ts>)) TTuple(TTuple<Us...>&& InValue)
: Super(NAMESPACE_PRIVATE::OtherTupleConstructor, MoveTemp(InValue)) : FSuper(NAMESPACE_PRIVATE::OtherTupleConstructor, MoveTemp(InValue))
{ } { }
/** Copies/moves content of other into a new instance. */ /** Copies/moves content of other into a new instance. */
@ -362,7 +371,7 @@ public:
&& (true && ... && CAssignableFrom<Ts&, const Us&>)) && (true && ... && CAssignableFrom<Ts&, const Us&>))
FORCEINLINE constexpr TTuple& operator=(const TTuple<Us...>& InValue) FORCEINLINE constexpr TTuple& operator=(const TTuple<Us...>& InValue)
{ {
Helper::Assign(*this, InValue); FHelper::Assign(*this, InValue);
return *this; return *this;
} }
@ -371,7 +380,7 @@ public:
&& (true && ... && CAssignableFrom<Ts&, Us&&>)) && (true && ... && CAssignableFrom<Ts&, Us&&>))
FORCEINLINE constexpr TTuple& operator=(TTuple<Us...>&& InValue) FORCEINLINE constexpr TTuple& operator=(TTuple<Us...>&& InValue)
{ {
Helper::Assign(*this, MoveTemp(InValue)); FHelper::Assign(*this, MoveTemp(InValue));
return *this; return *this;
} }
@ -396,8 +405,8 @@ public:
template <typename... Us> requires (sizeof...(Ts) == sizeof...(Us) && NAMESPACE_PRIVATE::CTTupleSynthThreeWayComparable<TTypeSequence<Ts...>, TTypeSequence<Us...>>) template <typename... Us> requires (sizeof...(Ts) == sizeof...(Us) && NAMESPACE_PRIVATE::CTTupleSynthThreeWayComparable<TTypeSequence<Ts...>, TTypeSequence<Us...>>)
NODISCARD friend FORCEINLINE constexpr TCommonComparisonCategory<TSynthThreeWayResult<Ts, Us>...> operator<=>(const TTuple& LHS, const TTuple<Us...>& RHS) NODISCARD friend FORCEINLINE constexpr TCommonComparisonCategory<TSynthThreeWayResult<Ts, Us>...> operator<=>(const TTuple& LHS, const TTuple<Us...>& RHS)
{ {
using R = TCommonComparisonCategory<TSynthThreeWayResult<Ts, Us>...>; using FResult = TCommonComparisonCategory<TSynthThreeWayResult<Ts, Us>...>;
return NAMESPACE_PRIVATE::TTupleThreeWay<R, TMakeIndexSequence<sizeof...(Ts)>>::Do(LHS, RHS); return NAMESPACE_PRIVATE::TTupleThreeWay<FResult, TMakeIndexSequence<sizeof...(Ts)>>::Do(LHS, RHS);
} }
/** Extracts the Ith element from the tuple. I must be an integer value in [0, sizeof...(Ts)). */ /** Extracts the Ith element from the tuple. I must be an integer value in [0, sizeof...(Ts)). */
@ -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>>(); } 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. */ /** 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 Helper::Apply(Forward<F>(Func), static_cast< 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 Helper::Apply(Forward<F>(Func), static_cast<const 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, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) volatile& { return Helper::Apply(Forward<F>(Func), static_cast< volatile 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, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const volatile& { return Helper::Apply(Forward<F>(Func), static_cast<const 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 Helper::Apply(Forward<F>(Func), static_cast< 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 Helper::Apply(Forward<F>(Func), static_cast<const 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, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) volatile&& { return Helper::Apply(Forward<F>(Func), static_cast< volatile 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, Ts...>) FORCEINLINE constexpr decltype(auto) Apply(F&& Func) const volatile&& { return Helper::Apply(Forward<F>(Func), static_cast<const 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. */ /** 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) & { 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&&, 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, Ts>) FORCEINLINE constexpr void Visit(F&& Func) volatile& { VisitTuple(Forward<F>(Func), static_cast< volatile 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, 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&&, 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&&, 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&&, 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, Ts>) FORCEINLINE constexpr void Visit(F&& Func) volatile&& { VisitTuple(Forward<F>(Func), static_cast< volatile 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, 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&&, 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. */ /** 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) && ... && 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 && 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) && ... && 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 && 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) && ... && 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 && 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&&, 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 && 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) && ... && 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 && 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) && ... && 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 && 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) && ... && 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 && 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&&, 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. */ /** 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) & { 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, 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&&, 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, 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&&, 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, 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&&, 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) && { 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) && { 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, 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&&, 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, 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&&, 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, 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&&, 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. */ /** 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 Helper::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) & { 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 Helper::Transform(Forward<F>(Func), static_cast<const 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, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) volatile& { return Helper::Transform(Forward<F>(Func), static_cast< volatile 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, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const volatile& { return Helper::Transform(Forward<F>(Func), static_cast<const 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 Helper::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) && { 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 Helper::Transform(Forward<F>(Func), static_cast<const 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, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) volatile&& { return Helper::Transform(Forward<F>(Func), static_cast< volatile 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, Ts> && !CSameAs<void, TInvokeResult<F, Ts>>)) NODISCARD FORCEINLINE constexpr decltype(auto) Transform(F&& Func) const volatile&& { return Helper::Transform(Forward<F>(Func), static_cast<const 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. */ /** 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 Helper::template Construct<T>(static_cast< 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 Helper::template Construct<T>(static_cast<const 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, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() volatile& { return Helper::template Construct<T>(static_cast< volatile 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, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() const volatile& { return Helper::template Construct<T>(static_cast<const 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 Helper::template Construct<T>(static_cast< 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 Helper::template Construct<T>(static_cast<const 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, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() volatile&& { return Helper::template Construct<T>(static_cast< volatile 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, Ts...>) NODISCARD FORCEINLINE constexpr T Construct() const volatile&& { return Helper::template Construct<T>(static_cast<const 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. */ /** @return The number of elements in the tuple. */
NODISCARD static FORCEINLINE constexpr size_t Num() { return sizeof...(Ts); } NODISCARD static FORCEINLINE constexpr size_t Num() { return sizeof...(Ts); }
@ -555,13 +564,13 @@ struct TTupleCatResultImpl;
template <typename... Ts, typename... TTupleTypes> template <typename... Ts, typename... TTupleTypes>
struct TTupleCatResultImpl<TTuple<Ts...>, TTupleTypes...> struct TTupleCatResultImpl<TTuple<Ts...>, TTupleTypes...>
{ {
using Type = typename TTupleCatResultImpl<TTupleTypes..., Ts...>::Type; using FType = typename TTupleCatResultImpl<TTupleTypes..., Ts...>::FType;
}; };
template <typename... Ts> template <typename... Ts>
struct TTupleCatResultImpl<FTupleEndFlag, Ts...> struct TTupleCatResultImpl<FTupleEndFlag, Ts...>
{ {
using Type = TTuple<Ts...>; using FType = TTuple<Ts...>;
}; };
template <typename R, typename Indices> template <typename R, typename Indices>
@ -571,14 +580,14 @@ template <typename... RTypes, size_t... Indices>
struct TTupleCatMake<TTuple<RTypes...>, TIndexSequence<Indices...>> struct TTupleCatMake<TTuple<RTypes...>, TIndexSequence<Indices...>>
{ {
template <typename T, typename U> template <typename T, typename U>
struct ForwardType { using Type = TConditional<CRValueReference<T>, TRemoveReference<U>&&, U>; }; struct FForwardType { using FType = TConditional<CRValueReference<T>, TRemoveReference<U>&&, U>; };
template <typename TTupleType> template <typename TTupleType>
FORCEINLINE static constexpr TTuple<RTypes...> Do(TTupleType&& InValue) FORCEINLINE static constexpr TTuple<RTypes...> Do(TTupleType&& InValue)
{ {
return TTuple<RTypes...> return TTuple<RTypes...>
( (
static_cast<typename ForwardType<RTypes, decltype(Forward<TTupleType>(InValue).template GetValue<Indices>())>::Type> static_cast<typename FForwardType<RTypes, decltype(Forward<TTupleType>(InValue).template GetValue<Indices>())>::FType>
( (
Forward<TTupleType>(InValue).template GetValue<Indices>() Forward<TTupleType>(InValue).template GetValue<Indices>()
)... )...
@ -642,15 +651,15 @@ struct TTupleVisitImpl<TIndexSequence<>>
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
template <typename... TTupleTypes> requires (true && ... && CTTuple<TRemoveCVRef<TTupleTypes>>) template <typename... TTupleTypes> requires (true && ... && CTTuple<TRemoveCVRef<TTupleTypes>>)
using TTupleCatResult = typename NAMESPACE_PRIVATE::TTupleCatResultImpl<TRemoveReference<TTupleTypes>..., NAMESPACE_PRIVATE::FTupleEndFlag>::Type;; using TTupleCatResult = typename NAMESPACE_PRIVATE::TTupleCatResultImpl<TRemoveReference<TTupleTypes>..., NAMESPACE_PRIVATE::FTupleEndFlag>::FType;
/** Creates a tuple by concatenating any number of tuples. */ /** Creates a tuple by concatenating any number of tuples. */
template <typename... TTupleTypes> requires (true && ... && CTTuple<TRemoveCVRef<TTupleTypes>>) template <typename... TTupleTypes> requires (true && ... && CTTuple<TRemoveCVRef<TTupleTypes>>)
FORCEINLINE constexpr decltype(auto) TupleCat(TTupleTypes&&... Args) FORCEINLINE constexpr decltype(auto) TupleCat(TTupleTypes&&... Args)
{ {
using R = TTupleCatResult<TTupleTypes...>; using FResult = TTupleCatResult<TTupleTypes...>;
if constexpr (sizeof...(Args) == 0) return R(); if constexpr (sizeof...(Args) == 0) return FResult();
else return NAMESPACE_PRIVATE::TTupleCatImpl<R>::Do(Forward<TTupleTypes>(Args)...); else return NAMESPACE_PRIVATE::TTupleCatImpl<FResult>::Do(Forward<TTupleTypes>(Args)...);
} }
/** /**
@ -679,20 +688,22 @@ FORCEINLINE constexpr void VisitTuple(F&& Func, FirstTupleType&& FirstTuple, Tup
template <typename... Ts, typename... Us> requires (requires { typename TTuple<TCommonType<Ts, Us>...>; }) template <typename... Ts, typename... Us> requires (requires { typename TTuple<TCommonType<Ts, Us>...>; })
struct TBasicCommonType<TTuple<Ts...>, TTuple<Us...>> struct TBasicCommonType<TTuple<Ts...>, TTuple<Us...>>
{ {
using Type = TTuple<TCommonType<Ts, Us>...>; using FType = TTuple<TCommonType<Ts, Us>...>;
}; };
template <typename... Ts, typename... Us, template<typename> typename TQualifiers, template<typename> typename UQualifiers> template <typename... Ts, typename... Us, template<typename> typename TQualifiers, template<typename> typename UQualifiers>
requires (requires { typename TTuple<TCommonReference<TQualifiers<Ts>, UQualifiers<Us>>...>; }) requires (requires { typename TTuple<TCommonReference<TQualifiers<Ts>, UQualifiers<Us>>...>; })
struct TBasicCommonReference<TTuple<Ts...>, TTuple<Us...>, TQualifiers, UQualifiers> struct TBasicCommonReference<TTuple<Ts...>, TTuple<Us...>, TQualifiers, UQualifiers>
{ {
using Type = TTuple<TCommonReference<TQualifiers<Ts>, UQualifiers<Us>>...>; using FType = TTuple<TCommonReference<TQualifiers<Ts>, UQualifiers<Us>>...>;
}; };
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END
// ReSharper disable CppInconsistentNaming
NAMESPACE_STD_BEGIN NAMESPACE_STD_BEGIN
// Support structure binding, should not be directly used. // Support structure binding, should not be directly used.
@ -718,3 +729,5 @@ template <size_t Index, typename ...Ts> FORCEINLINE constexpr decltype(auto) get
NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft) NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END NAMESPACE_REDCRAFT_END
// ReSharper restore CppInconsistentNaming

View File

@ -94,6 +94,20 @@ FORCEINLINE constexpr size_t GetTypeHash(const T& A)
return GetTypeHash(A.hash_code()); return GetTypeHash(A.hash_code());
} }
/** Overloads the GetTypeHash algorithm for arrays. */
template <typename T, size_t N> requires (requires(const T& A) { { GetTypeHash(A) } -> CSameAs<size_t>; })
FORCEINLINE constexpr size_t GetTypeHash(T(&A)[N])
{
size_t Result = 3516520171;
for (size_t Index = 0; Index < N; ++Index)
{
Result = HashCombine(Result, GetTypeHash(A[Index]));
}
return Result;
}
template <typename T> template <typename T>
concept CHashable = requires(const T& A) { { GetTypeHash(A) } -> CSameAs<size_t>; }; concept CHashable = requires(const T& A) { { GetTypeHash(A) } -> CSameAs<size_t>; };

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "TypeTraits/CompositeType.h"
#include "TypeTraits/Miscellaneous.h" #include "TypeTraits/Miscellaneous.h"
#include "TypeTraits/SupportedOperations.h" #include "TypeTraits/SupportedOperations.h"
@ -24,8 +23,8 @@ void AsConst(const T&& Ref) = delete;
template <typename T> template <typename T>
FORCEINLINE constexpr TRemoveReference<T>&& MoveTemp(T&& Obj) FORCEINLINE constexpr TRemoveReference<T>&& MoveTemp(T&& Obj)
{ {
using CastType = TRemoveReference<T>; using FCastType = TRemoveReference<T>;
return static_cast<CastType&&>(Obj); return static_cast<FCastType&&>(Obj);
} }
/** CopyTemp will enforce the creation of an rvalue which can bind to rvalue reference parameters. */ /** CopyTemp will enforce the creation of an rvalue which can bind to rvalue reference parameters. */
@ -73,6 +72,16 @@ FORCEINLINE constexpr void Swap(T& A, T& B)
B = MoveTemp(Temp); B = MoveTemp(Temp);
} }
/** Overloads the Swap algorithm for arrays. */
template <typename T, size_t N> requires (requires(T& A, T& B) { Swap(A, B); })
FORCEINLINE constexpr void Swap(T(&A)[N], T(&B)[N])
{
for (size_t Index = 0; Index != N; ++Index)
{
Swap(A[Index], B[Index]);
}
}
/** Replaces the value of 'A' with 'B' and returns the old value of 'A'. */ /** Replaces the value of 'A' with 'B' and returns the old value of 'A'. */
template <typename T, typename U = T> requires (CMoveConstructible<T> && CAssignableFrom<T&, U>) template <typename T, typename U = T> requires (CMoveConstructible<T> && CAssignableFrom<T&, U>)
FORCEINLINE constexpr T Exchange(T& A, U&& B) FORCEINLINE constexpr T Exchange(T& A, U&& B)

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "CoreTypes.h" #include "CoreTypes.h"
#include "Ranges/Utility.h"
#include "Templates/Meta.h" #include "Templates/Meta.h"
#include "Templates/Invoke.h" #include "Templates/Invoke.h"
#include "Templates/Utility.h" #include "Templates/Utility.h"
@ -40,30 +41,30 @@ struct TVariantAlternativeImpl;
template <size_t I, typename... Ts> template <size_t I, typename... Ts>
struct TVariantAlternativeImpl<I, TVariant<Ts...>> struct TVariantAlternativeImpl<I, TVariant<Ts...>>
{ {
using Type = Meta::TType<I, TTypeSequence<Ts...>>; using FType = Meta::TType<I, TTypeSequence<Ts...>>;
}; };
template <typename T, typename TSequence> template <typename T, typename TSequence>
struct TVariantOverloadType struct TVariantOverloadType
{ {
using FrontType = Meta::TFront<TSequence>; using FFrontType = Meta::TFront<TSequence>;
using NextSequence = Meta::TPop<TSequence>; using FNextSequence = Meta::TPop<TSequence>;
using NextUniqueSequence = typename TVariantOverloadType<T, NextSequence>::Type; using FNextUniqueSequence = typename TVariantOverloadType<T, FNextSequence>::FType;
// T_i x[] = { Forward<T>(t) }; // T_i x[] = { Forward<T>(t) };
static constexpr bool bConditional = requires { DeclVal<void(FrontType(&&)[1])>()({ DeclVal<T>() }); }; static constexpr bool bConditional = requires { DeclVal<void(FFrontType(&&)[1])>()({ DeclVal<T>() }); };
using Type = TConditional<bConditional, Meta::TPush<FrontType, NextUniqueSequence>, NextUniqueSequence>; using FType = TConditional<bConditional, Meta::TPush<FFrontType, FNextUniqueSequence>, FNextUniqueSequence>;
}; };
template <typename T> template <typename T>
struct TVariantOverloadType<T, TTypeSequence<>> struct TVariantOverloadType<T, TTypeSequence<>>
{ {
using Type = TTypeSequence<>; using FType = TTypeSequence<>;
}; };
template <typename T, typename... Ts> template <typename T, typename... Ts>
using TVariantSelectedType = Meta::TOverloadResolution<T, typename NAMESPACE_PRIVATE::TVariantOverloadType<T, TTypeSequence<Ts...>>::Type>; using TVariantSelectedType = Meta::TOverloadResolution<T, typename NAMESPACE_PRIVATE::TVariantOverloadType<T, TTypeSequence<Ts...>>::FType>;
NAMESPACE_PRIVATE_END NAMESPACE_PRIVATE_END
@ -77,7 +78,7 @@ template <typename T, CTVariant U>
inline constexpr size_t TVariantIndex = NAMESPACE_PRIVATE::TVariantIndexImpl<T, TRemoveCV<U>>::Value; inline constexpr size_t TVariantIndex = NAMESPACE_PRIVATE::TVariantIndexImpl<T, TRemoveCV<U>>::Value;
template <size_t I, CTVariant U> template <size_t I, CTVariant U>
using TVariantAlternative = TCopyCV<U, typename NAMESPACE_PRIVATE::TVariantAlternativeImpl<I, TRemoveCV<U>>::Type>; using TVariantAlternative = TCopyCV<U, typename NAMESPACE_PRIVATE::TVariantAlternativeImpl<I, TRemoveCV<U>>::FType>;
/** /**
* The class template TVariant represents a type-safe union. An instance of TVariant * The class template TVariant represents a type-safe union. An instance of TVariant
@ -113,7 +114,7 @@ public:
{ {
if (IsValid()) MoveConstructImpl[InValue.GetIndex()](&Value, &InValue.Value); if (IsValid()) MoveConstructImpl[InValue.GetIndex()](&Value, &InValue.Value);
} }
/** /**
* Converting constructor. Constructs a variant holding the alternative type that would be selected * Converting constructor. Constructs a variant holding the alternative type that would be selected
* by overload resolution for the expression F(Forward<T>(InValue)) if there was an overload of * by overload resolution for the expression F(Forward<T>(InValue)) if there was an overload of
@ -126,7 +127,7 @@ public:
&& !CSameAs<TVariant, TRemoveCVRef<T>>) && !CSameAs<TVariant, TRemoveCVRef<T>>)
FORCEINLINE constexpr TVariant(T&& InValue) : TVariant(InPlaceType<NAMESPACE_PRIVATE::TVariantSelectedType<T, Ts...>>, Forward<T>(InValue)) FORCEINLINE constexpr TVariant(T&& InValue) : TVariant(InPlaceType<NAMESPACE_PRIVATE::TVariantSelectedType<T, Ts...>>, Forward<T>(InValue))
{ } { }
/** Constructs a variant with the specified alternative T and initializes the contained value with the arguments Forward<Us>(Args).... */ /** Constructs a variant with the specified alternative T and initializes the contained value with the arguments Forward<Us>(Args).... */
template <typename T, typename... Us> requires (CConstructibleFrom<T, Us...>) template <typename T, typename... Us> requires (CConstructibleFrom<T, Us...>)
FORCEINLINE constexpr explicit TVariant(TInPlaceType<T>, Us&&... Args) FORCEINLINE constexpr explicit TVariant(TInPlaceType<T>, Us&&... Args)
@ -139,10 +140,10 @@ public:
FORCEINLINE constexpr explicit TVariant(TInPlaceIndex<I>, Us&&... Args) FORCEINLINE constexpr explicit TVariant(TInPlaceIndex<I>, Us&&... Args)
: TypeIndex(I) : TypeIndex(I)
{ {
using SelectedType = TVariantAlternative<I, TVariant<Ts...>>; using FSelectedType = TVariantAlternative<I, TVariant<Ts...>>;
new (&Value) SelectedType(Forward<Us>(Args)...); new (&Value) FSelectedType(Forward<Us>(Args)...);
} }
/** Constructs a variant with the specified alternative T and initializes the contained value with the arguments IL, Forward<Us>(Args).... */ /** Constructs a variant with the specified alternative T and initializes the contained value with the arguments IL, Forward<Us>(Args).... */
template <typename T, typename U, typename... Us> requires (CConstructibleFrom<T, initializer_list<U>, Us...>) template <typename T, typename U, typename... Us> requires (CConstructibleFrom<T, initializer_list<U>, Us...>)
FORCEINLINE constexpr explicit TVariant(TInPlaceType<T>, initializer_list<U> IL, Us&&... Args) FORCEINLINE constexpr explicit TVariant(TInPlaceType<T>, initializer_list<U> IL, Us&&... Args)
@ -155,8 +156,8 @@ public:
FORCEINLINE constexpr explicit TVariant(TInPlaceIndex<I>, initializer_list<T> IL, Us&&... Args) FORCEINLINE constexpr explicit TVariant(TInPlaceIndex<I>, initializer_list<T> IL, Us&&... Args)
: TypeIndex(I) : TypeIndex(I)
{ {
using SelectedType = TVariantAlternative<I, TVariant<Ts...>>; using FSelectedType = TVariantAlternative<I, TVariant<Ts...>>;
new (&Value) SelectedType(IL, Forward<Us>(Args)...); new (&Value) FSelectedType(IL, Forward<Us>(Args)...);
} }
/** Destroys the contained object, if any, as if by a call to Reset(). */ /** Destroys the contained object, if any, as if by a call to Reset(). */
@ -185,7 +186,7 @@ public:
if (GetIndex() == InValue.GetIndex()) CopyAssignImpl[InValue.GetIndex()](&Value, &InValue.Value); if (GetIndex() == InValue.GetIndex()) CopyAssignImpl[InValue.GetIndex()](&Value, &InValue.Value);
else else
{ {
Reset(); Reset();
CopyConstructImpl[InValue.GetIndex()](&Value, &InValue.Value); CopyConstructImpl[InValue.GetIndex()](&Value, &InValue.Value);
TypeIndex = static_cast<uint8>(InValue.GetIndex()); TypeIndex = static_cast<uint8>(InValue.GetIndex());
@ -224,14 +225,14 @@ public:
template <typename T> requires (requires { typename NAMESPACE_PRIVATE::TVariantSelectedType<T, Ts...>; }) template <typename T> requires (requires { typename NAMESPACE_PRIVATE::TVariantSelectedType<T, Ts...>; })
FORCEINLINE constexpr TVariant& operator=(T&& InValue) FORCEINLINE constexpr TVariant& operator=(T&& InValue)
{ {
using SelectedType = NAMESPACE_PRIVATE::TVariantSelectedType<T, Ts...>; using FSelectedType = NAMESPACE_PRIVATE::TVariantSelectedType<T, Ts...>;
if (GetIndex() == TVariantIndex<SelectedType, TVariant<Ts...>>) GetValue<SelectedType>() = Forward<T>(InValue); if (GetIndex() == TVariantIndex<FSelectedType, TVariant<Ts...>>) GetValue<FSelectedType>() = Forward<T>(InValue);
else else
{ {
Reset(); Reset();
new (&Value) SelectedType(Forward<T>(InValue)); new (&Value) FSelectedType(Forward<T>(InValue));
TypeIndex = TVariantIndex<SelectedType, TVariant<Ts...>>; TypeIndex = TVariantIndex<FSelectedType, TVariant<Ts...>>;
} }
return *this; return *this;
@ -277,7 +278,7 @@ public:
/** @return true if instance does not contain a value, otherwise false. */ /** @return true if instance does not contain a value, otherwise false. */
NODISCARD FORCEINLINE constexpr bool operator==(FInvalid) const& { return !IsValid(); } NODISCARD FORCEINLINE constexpr bool operator==(FInvalid) const& { return !IsValid(); }
/** Equivalent to Emplace<I>(Forward<Us>(Args)...), where I is the zero-based index of T in Types.... */ /** Equivalent to Emplace<I>(Forward<Us>(Args)...), where I is the zero-based index of T in Types.... */
template <typename T, typename... Us> requires (CConstructibleFrom<T, Us...>) template <typename T, typename... Us> requires (CConstructibleFrom<T, Us...>)
FORCEINLINE constexpr T& Emplace(Us&&... Args) FORCEINLINE constexpr T& Emplace(Us&&... Args)
@ -290,7 +291,7 @@ public:
* Then direct-initializes the contained value as if constructing a value of type T with the arguments Forward<Us>(Args).... * Then direct-initializes the contained value as if constructing a value of type T with the arguments Forward<Us>(Args)....
* *
* @param Args - The arguments to be passed to the constructor of the contained object. * @param Args - The arguments to be passed to the constructor of the contained object.
* *
* @return A reference to the new contained object. * @return A reference to the new contained object.
*/ */
template <size_t I, typename... Us> requires (I < sizeof...(Ts) template <size_t I, typename... Us> requires (I < sizeof...(Ts)
@ -299,13 +300,13 @@ public:
{ {
Reset(); Reset();
using SelectedType = TVariantAlternative<I, TVariant<Ts...>>; using FSelectedType = TVariantAlternative<I, TVariant<Ts...>>;
SelectedType* Result = new (&Value) SelectedType(Forward<Us>(Args)...); FSelectedType* Result = new (&Value) FSelectedType(Forward<Us>(Args)...);
TypeIndex = I; TypeIndex = I;
return *Result; return *Result;
} }
/** Equivalent to Emplace<I>(IL, Forward<Us>(Args)...), where I is the zero-based index of T in Types.... */ /** Equivalent to Emplace<I>(IL, Forward<Us>(Args)...), where I is the zero-based index of T in Types.... */
template <typename T, typename U, typename... Us> requires (CConstructibleFrom<T, initializer_list<U>, Us...>) template <typename T, typename U, typename... Us> requires (CConstructibleFrom<T, initializer_list<U>, Us...>)
FORCEINLINE constexpr T& Emplace(initializer_list<U> IL, Us&&... Args) FORCEINLINE constexpr T& Emplace(initializer_list<U> IL, Us&&... Args)
@ -318,7 +319,7 @@ public:
* Then direct-initializes the contained value as if constructing a value of type T with the arguments IL, Forward<Us>(Args).... * Then direct-initializes the contained value as if constructing a value of type T with the arguments IL, Forward<Us>(Args)....
* *
* @param IL, Args - The arguments to be passed to the constructor of the contained object. * @param IL, Args - The arguments to be passed to the constructor of the contained object.
* *
* @return A reference to the new contained object. * @return A reference to the new contained object.
*/ */
template <size_t I, typename T, typename... Us> requires (I < sizeof...(Ts) template <size_t I, typename T, typename... Us> requires (I < sizeof...(Ts)
@ -327,8 +328,8 @@ public:
{ {
Reset(); Reset();
using SelectedType = TVariantAlternative<I, TVariant<Ts...>>; using FSelectedType = TVariantAlternative<I, TVariant<Ts...>>;
SelectedType* Result = new (&Value) SelectedType(IL, Forward<Us>(Args)...); FSelectedType* Result = new (&Value) FSelectedType(IL, Forward<Us>(Args)...);
TypeIndex = I; TypeIndex = I;
return *Result; return *Result;
@ -423,7 +424,7 @@ public:
} }
private: private:
static constexpr const type_info* TypeInfos[] = { &typeid(Ts)... }; static constexpr const type_info* TypeInfos[] = { &typeid(Ts)... };
using FCopyConstructImpl = void(*)(void*, const void*); using FCopyConstructImpl = void(*)(void*, const void*);
@ -432,11 +433,11 @@ private:
using FMoveAssignImpl = void(*)(void*, void*); using FMoveAssignImpl = void(*)(void*, void*);
using FDestroyImpl = 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 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 (reinterpret_cast<Ts*>(A), reinterpret_cast< Ts*>(B)); else checkf(false, TEXT("The type '%s' is not move 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 (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 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 (reinterpret_cast<Ts*>(A), reinterpret_cast< Ts*>(B)); else checkf(false, TEXT("The type '%s' is not move 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 (reinterpret_cast<Ts*>(A) ); else checkf(false, TEXT("The type '%s' is not destructible."), 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; TAlignedUnion<1, Ts...> Value;
uint8 TypeIndex; uint8 TypeIndex;
@ -448,7 +449,7 @@ NAMESPACE_PRIVATE_BEGIN
template <typename F, typename... VariantTypes> template <typename F, typename... VariantTypes>
struct TVariantVisitImpl struct TVariantVisitImpl
{ {
struct GetTotalNum struct FGetTotalNum
{ {
FORCEINLINE static constexpr size_t Do() FORCEINLINE static constexpr size_t Do()
{ {
@ -464,10 +465,10 @@ struct TVariantVisitImpl
} }
return Result; return Result;
}; }
}; };
struct EncodeIndices struct FEncodeIndices
{ {
FORCEINLINE static constexpr size_t Do(initializer_list<size_t> Indices) FORCEINLINE static constexpr size_t Do(initializer_list<size_t> Indices)
{ {
@ -478,14 +479,14 @@ struct TVariantVisitImpl
for (size_t Index = 0; Index < sizeof...(VariantTypes); ++Index) for (size_t Index = 0; Index < sizeof...(VariantTypes); ++Index)
{ {
Result *= VariantNums[Index]; Result *= VariantNums[Index];
Result += GetData(Indices)[Index]; Result += Ranges::Begin(Indices)[Index];
} }
return Result; return Result;
}; }
}; };
struct DecodeExtent struct FDecodeExtent
{ {
FORCEINLINE static constexpr size_t Do(size_t EncodedIndex, size_t Extent) FORCEINLINE static constexpr size_t Do(size_t EncodedIndex, size_t Extent)
{ {
@ -497,76 +498,76 @@ struct TVariantVisitImpl
} }
return EncodedIndex % VariantNums[Extent]; return EncodedIndex % VariantNums[Extent];
}; }
}; };
template <size_t EncodedIndex, typename> template <size_t EncodedIndex, typename>
struct InvokeEncoded; struct TInvokeEncoded;
template <size_t EncodedIndex, size_t... ExtentIndices> template <size_t EncodedIndex, size_t... ExtentIndices>
struct InvokeEncoded<EncodedIndex, TIndexSequence<ExtentIndices...>> struct TInvokeEncoded<EncodedIndex, TIndexSequence<ExtentIndices...>>
{ {
FORCEINLINE static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants) FORCEINLINE static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants)
{ {
return Invoke(Forward<F>(Func), Forward<VariantTypes>(Variants).template GetValue<DecodeExtent::Do(EncodedIndex, ExtentIndices)>()...); return Invoke(Forward<F>(Func), Forward<VariantTypes>(Variants).template GetValue<FDecodeExtent::Do(EncodedIndex, ExtentIndices)>()...);
} }
template <typename Ret> template <typename Ret>
struct Result struct TResult
{ {
FORCEINLINE static constexpr Ret Do(F&& Func, VariantTypes&&... Variants) FORCEINLINE static constexpr Ret Do(F&& Func, VariantTypes&&... Variants)
{ {
return InvokeResult<Ret>(Forward<F>(Func), Forward<VariantTypes>(Variants).template GetValue<DecodeExtent::Do(EncodedIndex, ExtentIndices)>()...); return InvokeResult<Ret>(Forward<F>(Func), Forward<VariantTypes>(Variants).template GetValue<FDecodeExtent::Do(EncodedIndex, ExtentIndices)>()...);
} }
}; };
}; };
template <typename> template <typename>
struct InvokeVariant; struct TInvokeVariant;
template <size_t... EncodedIndices> template <size_t... EncodedIndices>
struct InvokeVariant<TIndexSequence<EncodedIndices...>> struct TInvokeVariant<TIndexSequence<EncodedIndices...>>
{ {
FORCEINLINE static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants) FORCEINLINE static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants)
{ {
using ExtentIndices = TIndexSequenceFor<VariantTypes...>; using FExtentIndices = TIndexSequenceFor<VariantTypes...>;
using ResultType = TCommonType<decltype(InvokeEncoded<EncodedIndices, ExtentIndices>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...))...>; using FResultType = TCommonReference<decltype(TInvokeEncoded<EncodedIndices, FExtentIndices>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...))...>;
using InvokeImplType = ResultType(*)(F&&, VariantTypes&&...);
constexpr InvokeImplType InvokeImpl[] = { InvokeEncoded<EncodedIndices, ExtentIndices>::template Result<ResultType>::Do... }; using FInvokeImplType = FResultType(*)(F&&, VariantTypes&&...);
return InvokeImpl[EncodeIndices::Do({ Variants.GetIndex()... })](Forward<F>(Func), Forward<VariantTypes>(Variants)...); 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> template <typename Ret>
struct Result struct TResult
{ {
FORCEINLINE static constexpr Ret Do(F&& Func, VariantTypes&&... Variants) FORCEINLINE static constexpr Ret Do(F&& Func, VariantTypes&&... Variants)
{ {
using ExtentIndices = TIndexSequenceFor<VariantTypes...>; using FExtentIndices = TIndexSequenceFor<VariantTypes...>;
using InvokeImplType = Ret(*)(F&&, VariantTypes&&...); using FInvokeImplType = Ret(*)(F&&, VariantTypes&&...);
constexpr InvokeImplType InvokeImpl[] = { InvokeEncoded<EncodedIndices, ExtentIndices>::template Result<Ret>::Do... }; constexpr FInvokeImplType InvokeImpl[] = { TInvokeEncoded<EncodedIndices, FExtentIndices>::template TResult<Ret>::Do... };
return InvokeImpl[EncodeIndices::Do({ Variants.GetIndex()... })](Forward<F>(Func), Forward<VariantTypes>(Variants)...); return InvokeImpl[FEncodeIndices::Do({ Variants.GetIndex()... })](Forward<F>(Func), Forward<VariantTypes>(Variants)...);
} }
}; };
}; };
FORCEINLINE static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants) FORCEINLINE static constexpr decltype(auto) Do(F&& Func, VariantTypes&&... Variants)
{ {
return InvokeVariant<TMakeIndexSequence<GetTotalNum::Do()>>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...); return TInvokeVariant<TMakeIndexSequence<FGetTotalNum::Do()>>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...);
} }
template <typename Ret> template <typename Ret>
struct Result struct TResult
{ {
FORCEINLINE static constexpr Ret Do(F&& Func, VariantTypes&&... Variants) FORCEINLINE static constexpr Ret Do(F&& Func, VariantTypes&&... Variants)
{ {
return InvokeVariant<TMakeIndexSequence<GetTotalNum::Do()>>::template Result<Ret>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...); return TInvokeVariant<TMakeIndexSequence<FGetTotalNum::Do()>>::template TResult<Ret>::Do(Forward<F>(Func), Forward<VariantTypes>(Variants)...);
} }
}; };
}; };
@ -588,7 +589,7 @@ template <typename Ret, typename F, typename FirstVariantType, typename... Varia
constexpr Ret Visit(F&& Func, FirstVariantType&& FirstVariant, VariantTypes&&... Variants) 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().")); 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 Result<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) NAMESPACE_MODULE_END(Utility)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

Some files were not shown because too many files have changed in this diff Show More