#pragma once #include "Miscellaneous/CoreDefines.h" #include #include #include #if __cplusplus >= 202300L # include #endif NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) // ReSharper disable CppInconsistentNaming // Platform information macro #ifndef PLATFORM_NAME # error "PLATFORM_NAME must be defined." #endif #ifndef PLATFORM_WINDOWS # define PLATFORM_WINDOWS 0 #endif #ifndef PLATFORM_LINUX # define PLATFORM_LINUX 0 #endif #ifndef PLATFORM_UNKNOWN # define PLATFORM_UNKNOWN 0 #endif // Build information macro #ifndef BUILD_TYPE # error "BUILD_TYPE must be defined." #endif #ifndef BUILD_DEBUG # define BUILD_DEBUG 0 #endif #ifndef BUILD_DEVELOPMENT # define BUILD_DEVELOPMENT 0 #endif #ifndef BUILD_RELEASE # define BUILD_RELEASE 0 #endif #ifndef BUILD_UNKNOWN # define BUILD_UNKNOWN 0 #endif // Compiler information macro #ifndef PLATFORM_COMPILER_NAME # error "COMPILER_NAME must be defined." #endif #ifndef PLATFORM_COMPILER_MSVC # define PLATFORM_COMPILER_MSVC 0 #endif #ifndef PLATFORM_COMPILER_CLANG # define PLATFORM_COMPILER_CLANG 0 #endif #ifndef PLATFORM_COMPILER_GCC # define PLATFORM_COMPILER_GCC 0 #endif #ifndef PLATFORM_COMPILER_UNKNOWN # define PLATFORM_COMPILER_UNKNOWN 0 #endif // Architecture information macro #ifndef PLATFORM_CPU_X86_FAMILY # if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__) || defined(__x86_64__)) # define PLATFORM_CPU_X86_FAMILY 1 # else # define PLATFORM_CPU_X86_FAMILY 0 # endif #endif #ifndef PLATFORM_CPU_ARM_FAMILY # if (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || defined(_M_ARM64)) # define PLATFORM_CPU_ARM_FAMILY 1 # else # define PLATFORM_CPU_ARM_FAMILY 0 # endif #endif #ifndef PLATFORM_CPU_UNKNOWN_FAMILY # define PLATFORM_CPU_UNKNOWN_FAMILY (!(PLATFORM_CPU_X86_FAMILY || PLATFORM_CPU_ARM_FAMILY)) #endif // CPU bits information macro #ifndef PLATFORM_CPU_BITS # if (defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64)) # define PLATFORM_CPU_BITS 64 # elif (defined(_M_IX86) || defined(__i386__) || defined(__arm__) || defined(_M_ARM)) # define PLATFORM_CPU_BITS 32 # else # define PLATFORM_CPU_BITS 0 # endif #endif // Endian information macro #if !defined(PLATFORM_LITTLE_ENDIAN) && !defined(PLATFORM_BIG_ENDIAN) # if PLATFORM_COMPILER_MSVC # define PLATFORM_LITTLE_ENDIAN 1 # define PLATFORM_BIG_ENDIAN 0 # elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define PLATFORM_LITTLE_ENDIAN 1 # define PLATFORM_BIG_ENDIAN 0 # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define PLATFORM_LITTLE_ENDIAN 0 # define PLATFORM_BIG_ENDIAN 1 # else # define PLATFORM_LITTLE_ENDIAN 0 # define PLATFORM_BIG_ENDIAN 0 # endif # endif #endif #ifndef PLATFORM_LITTLE_ENDIAN # define PLATFORM_LITTLE_ENDIAN 0 #endif #ifndef PLATFORM_BIG_ENDIAN # define PLATFORM_BIG_ENDIAN 0 #endif #ifndef PLATFORM_CPU_MIXED_ENDIAN # define PLATFORM_MIXED_ENDIAN (!(PLATFORM_LITTLE_ENDIAN || PLATFORM_BIG_ENDIAN)) #endif // Integral type information macro #ifndef PLATFORM_HAS_INT8 # define PLATFORM_HAS_INT8 1 #endif #ifndef PLATFORM_HAS_INT16 # define PLATFORM_HAS_INT16 1 #endif #ifndef PLATFORM_HAS_INT32 # define PLATFORM_HAS_INT32 1 #endif #ifndef PLATFORM_HAS_INT64 # define PLATFORM_HAS_INT64 1 #endif #ifndef PLATFORM_HAS_INT128 # if defined(__SIZEOF_INT128__) # define PLATFORM_HAS_INT128 (__SIZEOF_INT128__ == 16) # else # define PLATFORM_HAS_INT128 0 # endif #endif #ifndef PLATFORM_INTMAX_BITS # if PLATFORM_HAS_INT128 # define PLATFORM_INTMAX_BITS 128 # else # define PLATFORM_INTMAX_BITS 64 # endif #endif #if !(PLATFORM_HAS_INT8 && PLATFORM_HAS_INT16 && PLATFORM_HAS_INT32 && PLATFORM_HAS_INT64) # error "64-bit and below integral types must be supported." #endif // Floating point type information macro #ifndef PLATFORM_HAS_FLOAT16 # if defined(__STDCPP_FLOAT16_T__) # define PLATFORM_HAS_FLOAT16 1 # else # define PLATFORM_HAS_FLOAT16 0 # endif #endif #ifndef PLATFORM_HAS_FLOAT32 # define PLATFORM_HAS_FLOAT32 1 #endif #ifndef PLATFORM_HAS_FLOAT64 # define PLATFORM_HAS_FLOAT64 1 #endif #ifndef PLATFORM_HAS_FLOAT128 # if defined(__STDCPP_FLOAT128_T__) # define PLATFORM_HAS_FLOAT128 1 # else # define PLATFORM_HAS_FLOAT128 0 # endif #endif #ifndef PLATFORM_HAS_BFLOAT16 # if defined(__STDCPP_BFLOAT16_T__) # define PLATFORM_HAS_BFLOAT16 1 # else # define PLATFORM_HAS_BFLOAT16 0 # endif #endif // Character type information macro #ifndef PLATFORM_HAS_WCHAR # define PLATFORM_HAS_WCHAR 1 #endif #ifndef PLATFORM_HAS_U8CHAR # ifdef __cpp_char8_t # define PLATFORM_HAS_U8CHAR 1 # else # define PLATFORM_HAS_U8CHAR 0 # endif #endif #ifndef PLATFORM_HAS_U16CHAR # ifdef __cpp_unicode_characters # define PLATFORM_HAS_U16CHAR 1 # else # define PLATFORM_HAS_U16CHAR 0 # endif #endif #ifndef PLATFORM_HAS_U32CHAR # ifdef __cpp_unicode_characters # define PLATFORM_HAS_U32CHAR 1 # else # define PLATFORM_HAS_U32CHAR 0 # endif #endif #ifndef PLATFORM_HAS_UNICODECHAR # ifdef __cpp_unicode_characters # define PLATFORM_HAS_UNICODECHAR 1 # else # define PLATFORM_HAS_UNICODECHAR 0 # endif #endif #if !(PLATFORM_HAS_WCHAR && PLATFORM_HAS_U8CHAR && PLATFORM_HAS_U16CHAR && PLATFORM_HAS_U32CHAR) # error "All character types must be supported." #endif // Function type macros #if PLATFORM_COMPILER_MSVC # define VARARGS __cdecl # define CDECL __cdecl # define STDCALL __stdcall # define FORCEINLINE __forceinline # define FORCENOINLINE __declspec(noinline) # define RESTRICT __restrict #elif PLATFORM_COMPILER_CLANG || PLATFORM_COMPILER_GCC # define VARARGS # define CDECL # define STDCALL # define FORCENOINLINE __attribute__((noinline)) # define RESTRICT __restrict # if BUILD_DEBUG # define FORCEINLINE inline # else # define FORCEINLINE inline __attribute__((always_inline)) # endif #else # define VARARGS # define CDECL # define STDCALL # define FORCEINLINE # define FORCENOINLINE # define RESTRICT __restrict #endif // DLL export and import macros #if PLATFORM_COMPILER_MSVC # define DLLEXPORT __declspec(dllexport) # define DLLIMPORT __declspec(dllimport) #elif PLATFORM_COMPILER_CLANG || PLATFORM_COMPILER_GCC # define DLLEXPORT __attribute__((visibility("default"))) # define DLLIMPORT __attribute__((visibility("default"))) #else # error "DLL export and import macros must be defined." #endif // Optimization macros #if PLATFORM_COMPILER_MSVC # define PRAGMA_DISABLE_OPTIMIZATION_ACTUAL _Pragma("optimize(\"\", off)") # define PRAGMA_ENABLE_OPTIMIZATION_ACTUAL _Pragma("optimize(\"\", on)") #elif PLATFORM_COMPILER_CLANG # define PRAGMA_DISABLE_OPTIMIZATION_ACTUAL _Pragma("clang optimize off") # define PRAGMA_ENABLE_OPTIMIZATION_ACTUAL _Pragma("clang optimize on") #elif PLATFORM_COMPILER_GCC # define PRAGMA_DISABLE_OPTIMIZATION_ACTUAL _Pragma("GCC push_options") _Pragma("GCC optimize (\"O0\")") # define PRAGMA_ENABLE_OPTIMIZATION_ACTUAL _Pragma("GCC pop_options") #else # define PRAGMA_DISABLE_OPTIMIZATION_ACTUAL # define PRAGMA_ENABLE_OPTIMIZATION_ACTUAL #endif #if BUILD_DEBUG # define PRAGMA_DISABLE_OPTIMIZATION # define PRAGMA_ENABLE_OPTIMIZATION #else # define PRAGMA_DISABLE_OPTIMIZATION PRAGMA_DISABLE_OPTIMIZATION_ACTUAL # define PRAGMA_ENABLE_OPTIMIZATION PRAGMA_ENABLE_OPTIMIZATION_ACTUAL #endif // Signed integral types using int8 = NAMESPACE_STD::int8_t; using int16 = NAMESPACE_STD::int16_t; using int32 = NAMESPACE_STD::int32_t; using int64 = NAMESPACE_STD::int64_t; #if PLATFORM_HAS_INT128 using int128 = __int128; #endif using int8_least = NAMESPACE_STD::int_least8_t; using int16_least = NAMESPACE_STD::int_least16_t; using int32_least = NAMESPACE_STD::int_least32_t; using int64_least = NAMESPACE_STD::int_least64_t; #if PLATFORM_HAS_INT128 using int128_least = int128; #endif using int8_fast = NAMESPACE_STD::int_fast8_t; using int16_fast = NAMESPACE_STD::int_fast16_t; using int32_fast = NAMESPACE_STD::int_fast32_t; using int64_fast = NAMESPACE_STD::int_fast64_t; #if PLATFORM_HAS_INT128 using int128_fast = int128; #endif #if PLATFORM_HAS_INT128 using intmax = int128; #else using intmax = int64; #endif static_assert(sizeof(int8) == 1, "int8 must be 1 byte"); static_assert(sizeof(int16) == 2, "int16 must be 2 bytes"); static_assert(sizeof(int32) == 4, "int32 must be 4 bytes"); static_assert(sizeof(int64) == 8, "int64 must be 8 bytes"); static_assert(sizeof(int8_least) >= 1, "int8_least must be at least 1 byte"); static_assert(sizeof(int16_least) >= 2, "int16_least must be at least 2 bytes"); static_assert(sizeof(int32_least) >= 4, "int32_least must be at least 4 bytes"); static_assert(sizeof(int64_least) >= 8, "int64_least must be at least 8 bytes"); static_assert(sizeof(int8_fast) >= 1, "int8_fast must be at least 1 byte"); static_assert(sizeof(int16_fast) >= 2, "int16_fast must be at least 2 bytes"); static_assert(sizeof(int32_fast) >= 4, "int32_fast must be at least 4 bytes"); static_assert(sizeof(int64_fast) >= 8, "int64_fast must be at least 8 bytes"); static_assert(static_cast(0xFF) == -1, "int8 use two's complement"); static_assert(static_cast(0xFFFF) == -1, "int16 use two's complement"); static_assert(static_cast(0xFFFFFFFF) == -1, "int32 use two's complement"); static_assert(static_cast(0xFFFFFFFFFFFFFFFF) == -1, "int64 use two's complement"); // Unsigned integral types using uint = unsigned int; using byte = unsigned char; using uint8 = NAMESPACE_STD::uint8_t; using uint16 = NAMESPACE_STD::uint16_t; using uint32 = NAMESPACE_STD::uint32_t; using uint64 = NAMESPACE_STD::uint64_t; #if PLATFORM_HAS_INT128 using uint128 = unsigned __int128; #endif using uint8_least = NAMESPACE_STD::uint_least8_t; using uint16_least = NAMESPACE_STD::uint_least16_t; using uint32_least = NAMESPACE_STD::uint_least32_t; using uint64_least = NAMESPACE_STD::uint_least64_t; #if PLATFORM_HAS_INT128 using uint128_least = uint128; #endif using uint8_fast = NAMESPACE_STD::uint_fast8_t; using uint16_fast = NAMESPACE_STD::uint_fast16_t; using uint32_fast = NAMESPACE_STD::uint_fast32_t; using uint64_fast = NAMESPACE_STD::uint_fast64_t; #if PLATFORM_HAS_INT128 using uint128_fast = uint128; #endif #if PLATFORM_HAS_INT128 using uintmax = uint128; #else using uintmax = uint64; #endif static_assert(sizeof(uint8) == 1, "uint8 must be 1 byte"); static_assert(sizeof(uint16) == 2, "uint16 must be 2 bytes"); static_assert(sizeof(uint32) == 4, "uint32 must be 4 bytes"); static_assert(sizeof(uint64) == 8, "uint64 must be 8 bytes"); static_assert(sizeof(uint8_least) >= 1, "uint8_least must be at least 1 byte"); static_assert(sizeof(uint16_least) >= 2, "uint16_least must be at least 2 bytes"); static_assert(sizeof(uint32_least) >= 4, "uint32_least must be at least 4 bytes"); static_assert(sizeof(uint64_least) >= 8, "uint64_least must be at least 8 bytes"); static_assert(sizeof(uint8_fast) >= 1, "uint8_fast must be at least 1 byte"); static_assert(sizeof(uint16_fast) >= 2, "uint16_fast must be at least 2 bytes"); static_assert(sizeof(uint32_fast) >= 4, "uint32_fast must be at least 4 bytes"); static_assert(sizeof(uint64_fast) >= 8, "uint64_fast must be at least 8 bytes"); static_assert(static_cast(-1) > static_cast< uint8>(0), "uint8 must be unsigned"); static_assert(static_cast(-1) > static_cast(0), "uint16 must be unsigned"); static_assert(static_cast(-1) > static_cast(0), "uint32 must be unsigned"); static_assert(static_cast(-1) > static_cast(0), "uint64 must be unsigned"); // Floating point types #if PLATFORM_HAS_FLOAT16 using float16 = NAMESPACE_STD::float16_t; #endif #if PLATFORM_HAS_FLOAT32 # ifdef __STDCPP_FLOAT32_T__ using float32 = NAMESPACE_STD::float32_t; # else using float32 = float; # endif #endif #if PLATFORM_HAS_FLOAT64 # ifdef __STDCPP_FLOAT64_T__ using float64 = NAMESPACE_STD::float64_t; # else using float64 = double; # endif #endif #if PLATFORM_HAS_FLOAT128 using float128 = NAMESPACE_STD::float128_t; #endif #if PLATFORM_HAS_BFLOAT16 using bfloat16 = NAMESPACE_STD::bfloat16_t; #endif // Character types // The 'char' typically represents the user-preferred locale narrow encoded character set. // The 'wchar' typically represents the user-preferred locale wide encoded character set. // The 'u8char' typically represents the UTF-8 encoded unicode character set. // The 'u16char' typically represents the UTF-16 encoded unicode character set. // The 'u32char' typically represents the UTF-32 encoded unicode character set. // The 'unicodechar' typically represents the fixed-length encoded unicode character set. // The literals should preferentially use unicode character set instead of user-preferred locale character set. using wchar = wchar_t; using u8char = char8_t; using u16char = char16_t; using u32char = char32_t; using unicodechar = char32_t; static_assert(!PLATFORM_WINDOWS || sizeof(wchar) == sizeof(u16char), "wchar represents UTF-16 on Windows"); static_assert(!PLATFORM_LINUX || sizeof(wchar) == sizeof(u32char), "wchar represents UTF-32 on Linux"); // Pointer types using uintptr = NAMESPACE_STD::uintptr_t; using ptrdiff = NAMESPACE_STD::ptrdiff_t; using size_t = NAMESPACE_STD::size_t; static_assert(sizeof(uintptr) == sizeof(void*), "uintptr must be the same size as a pointer"); static_assert(sizeof(ptrdiff) == sizeof(void*), "ptrdiff must be the same size as a pointer"); static_assert(sizeof(size_t) == sizeof(void*), "size_t must be the same size as a pointer"); static_assert(static_cast(-1) > static_cast(0), "uintptr must be unsigned"); // Null types using null_t = decltype(NULL); using nullptr_t = NAMESPACE_STD::nullptr_t; // Define the TEXT macro NAMESPACE_PRIVATE_BEGIN #define TEXT_PASTE(X) X #define WTEXT_PASTE(X) L##X #define U8TEXT_PASTE(X) u8##X #define U16TEXT_PASTE(X) u##X #define U32TEXT_PASTE(X) U##X NAMESPACE_PRIVATE_END #define TEXT(X) TEXT_PASTE(X) #define WTEXT(X) WTEXT_PASTE(X) #define U8TEXT(X) U8TEXT_PASTE(X) #define U16TEXT(X) U16TEXT_PASTE(X) #define U32TEXT(X) U32TEXT_PASTE(X) #define UNICODETEXT(X) U32TEXT_PASTE(X) // ReSharper restore CppInconsistentNaming NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END