// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once #include #include #include #include #include // Force inline helper #ifndef ALWAYS_INLINE #if defined(_MSC_VER) #define ALWAYS_INLINE __forceinline #elif defined(__GNUC__) || defined(__clang__) #define ALWAYS_INLINE __attribute__((always_inline)) inline #else #define ALWAYS_INLINE inline #endif #endif // Force inline in non-debug helper #ifdef _DEBUG #define ALWAYS_INLINE_RELEASE inline #else #define ALWAYS_INLINE_RELEASE ALWAYS_INLINE #endif // unreferenced parameter macro #ifndef UNREFERENCED_VARIABLE #if defined(__GNUC__) || defined(__clang__) || defined(__EMSCRIPTEN__) #define UNREFERENCED_VARIABLE(P) (void)(P) #else #define UNREFERENCED_VARIABLE(P) (P) #endif #endif // countof macro #ifndef countof #ifdef _countof #define countof _countof #else template char (&__countof_ArraySizeHelper(T (&array)[N]))[N]; #define countof(array) (sizeof(__countof_ArraySizeHelper(array))) #endif #endif // offsetof macro #ifndef offsetof #define offsetof(st, m) ((size_t)((char*)&((st*)(0))->m - (char*)0)) #endif #ifdef __GNUC__ #define printflike(n, m) __attribute__((format(printf, n, m))) #else #define printflike(n, m) #endif // [[noreturn]] which can be used on function pointers. #ifdef _MSC_VER // __declspec(noreturn) produces error C3829. #define NORETURN_FUNCTION_POINTER #else #define NORETURN_FUNCTION_POINTER __attribute__((noreturn)) #endif // __assume, potentially enables optimization. #ifdef _MSC_VER #define ASSUME(x) __assume(x) #else #define ASSUME(x) \ do \ { \ if (!(x)) \ __builtin_unreachable(); \ } while (0) #endif // disable warnings that show up at warning level 4 // TODO: Move to build system instead #ifdef _MSC_VER #pragma warning(disable : 4201) // warning C4201: nonstandard extension used : nameless struct/union #pragma warning(disable : 4100) // warning C4100: 'Platform' : unreferenced formal parameter #pragma warning(disable : 4355) // warning C4355: 'this' : used in base member initializer list #endif using s8 = int8_t; using u8 = uint8_t; using s16 = int16_t; using u16 = uint16_t; using s32 = int32_t; using u32 = uint32_t; using s64 = int64_t; using u64 = uint64_t; // Enable use of static_assert in constexpr if template struct dependent_false : std::false_type { }; template struct dependent_int_false : std::false_type { }; // Architecture detection. #if defined(_MSC_VER) #if defined(_M_X64) #define CPU_ARCH_X64 1 #elif defined(_M_IX86) #define CPU_ARCH_X86 1 #elif defined(_M_ARM64) #define CPU_ARCH_ARM64 1 #elif defined(_M_ARM) #define CPU_ARCH_ARM32 1 #else #error Unknown architecture. #endif #elif defined(__GNUC__) || defined(__clang__) #if defined(__x86_64__) #define CPU_ARCH_X64 1 #elif defined(__i386__) #define CPU_ARCH_X86 1 #elif defined(__aarch64__) #define CPU_ARCH_ARM64 1 #elif defined(__arm__) #define CPU_ARCH_ARM32 1 #elif defined(__riscv) && __riscv_xlen == 64 #define CPU_ARCH_RISCV64 1 #else #error Unknown architecture. #endif #else #error Unknown compiler. #endif #if defined(CPU_ARCH_X64) #define CPU_ARCH_STR "x64" #elif defined(CPU_ARCH_X86) #define CPU_ARCH_STR "x86" #elif defined(CPU_ARCH_ARM32) #define CPU_ARCH_STR "arm32" #elif defined(CPU_ARCH_ARM64) #define CPU_ARCH_STR "arm64" #elif defined(CPU_ARCH_RISCV64) #define CPU_ARCH_STR "riscv64" #else #define CPU_ARCH_STR "Unknown" #endif // OS detection. #if defined(_WIN32) #define TARGET_OS_STR "Windows" #elif defined(__ANDROID__) #define TARGET_OS_STR "Android" #elif defined(__linux__) #define TARGET_OS_STR "Linux" #elif defined(__FreeBSD__) #define TARGET_OS_STR "FreeBSD" #elif defined(__APPLE__) #define TARGET_OS_STR "macOS" #else #define TARGET_OS_STR "Unknown" #endif // Host page sizes. #if defined(OVERRIDE_HOST_PAGE_SIZE) static constexpr u32 HOST_PAGE_SIZE = OVERRIDE_HOST_PAGE_SIZE; static constexpr u32 HOST_PAGE_MASK = HOST_PAGE_SIZE - 1; static constexpr u32 HOST_PAGE_SHIFT = std::bit_width(HOST_PAGE_MASK); #elif defined(__APPLE__) && defined(__aarch64__) static constexpr u32 HOST_PAGE_SIZE = 0x4000; static constexpr u32 HOST_PAGE_MASK = HOST_PAGE_SIZE - 1; static constexpr u32 HOST_PAGE_SHIFT = 14; #else static constexpr u32 HOST_PAGE_SIZE = 0x1000; static constexpr u32 HOST_PAGE_MASK = HOST_PAGE_SIZE - 1; static constexpr u32 HOST_PAGE_SHIFT = 12; #endif // Enum class bitwise operators #define IMPLEMENT_ENUM_CLASS_BITWISE_OPERATORS(type_) \ ALWAYS_INLINE constexpr type_ operator&(type_ lhs, type_ rhs) \ { \ return static_cast(static_cast::type>(lhs) & \ static_cast::type>(rhs)); \ } \ ALWAYS_INLINE constexpr type_ operator|(type_ lhs, type_ rhs) \ { \ return static_cast(static_cast::type>(lhs) | \ static_cast::type>(rhs)); \ } \ ALWAYS_INLINE constexpr type_ operator^(type_ lhs, type_ rhs) \ { \ return static_cast(static_cast::type>(lhs) ^ \ static_cast::type>(rhs)); \ } \ ALWAYS_INLINE constexpr type_ operator~(type_ val) \ { \ return static_cast(~static_cast::type>(val)); \ } \ ALWAYS_INLINE constexpr type_& operator&=(type_& lhs, type_ rhs) \ { \ lhs = static_cast(static_cast::type>(lhs) & \ static_cast::type>(rhs)); \ return lhs; \ } \ ALWAYS_INLINE constexpr type_& operator|=(type_& lhs, type_ rhs) \ { \ lhs = static_cast(static_cast::type>(lhs) | \ static_cast::type>(rhs)); \ return lhs; \ } \ ALWAYS_INLINE constexpr type_& operator^=(type_& lhs, type_ rhs) \ { \ lhs = static_cast(static_cast::type>(lhs) ^ \ static_cast::type>(rhs)); \ return lhs; \ }