duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

types.h (10368B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #pragma once
      5 #include <bit>
      6 #include <cstdint>
      7 #include <cstring>
      8 #include <limits>
      9 #include <type_traits>
     10 
     11 // Force inline helper
     12 #ifndef ALWAYS_INLINE
     13 #if defined(_MSC_VER)
     14 #define ALWAYS_INLINE __forceinline
     15 #elif defined(__GNUC__) || defined(__clang__)
     16 #define ALWAYS_INLINE __attribute__((always_inline)) inline
     17 #else
     18 #define ALWAYS_INLINE inline
     19 #endif
     20 #endif
     21 
     22 // Force inline in non-debug helper
     23 #ifdef _DEBUG
     24 #define ALWAYS_INLINE_RELEASE inline
     25 #else
     26 #define ALWAYS_INLINE_RELEASE ALWAYS_INLINE
     27 #endif
     28 
     29 // unreferenced parameter macro
     30 #ifndef UNREFERENCED_VARIABLE
     31 #if defined(__GNUC__) || defined(__clang__) || defined(__EMSCRIPTEN__)
     32 #define UNREFERENCED_VARIABLE(P) (void)(P)
     33 #else
     34 #define UNREFERENCED_VARIABLE(P) (P)
     35 #endif
     36 #endif
     37 
     38 // countof macro
     39 #ifndef countof
     40 #ifdef _countof
     41 #define countof _countof
     42 #else
     43 template<typename T, size_t N>
     44 char (&__countof_ArraySizeHelper(T (&array)[N]))[N];
     45 #define countof(array) (sizeof(__countof_ArraySizeHelper(array)))
     46 #endif
     47 #endif
     48 
     49 // offsetof macro. Need to use __builtin_offsetof(), otherwise it doesn't work in constant expressions.
     50 #if defined(__clang__) || defined(__GNUC__)
     51 #define OFFSETOF(st, m) __builtin_offsetof(st, m)
     52 #else
     53 #ifdef offsetof
     54 #define OFFSETOF(st, m) offsetof(st, m)
     55 #else
     56 #define OFFSETOF(st, m) ((size_t)((char*)&((st*)(0))->m - (char*)0))
     57 #endif
     58 #endif
     59 
     60 #ifdef __GNUC__
     61 #define printflike(n, m) __attribute__((format(printf, n, m)))
     62 #else
     63 #define printflike(n, m)
     64 #endif
     65 
     66 // [[noreturn]] which can be used on function pointers.
     67 #ifdef _MSC_VER
     68 // __declspec(noreturn) produces error C3829.
     69 #define NORETURN_FUNCTION_POINTER
     70 #else
     71 #define NORETURN_FUNCTION_POINTER __attribute__((noreturn))
     72 #endif
     73 
     74 // __assume, potentially enables optimization.
     75 #ifdef _MSC_VER
     76 #define ASSUME(x) __assume(x)
     77 #else
     78 #define ASSUME(x)                                                                                                      \
     79   do                                                                                                                   \
     80   {                                                                                                                    \
     81     if (!(x))                                                                                                          \
     82       __builtin_unreachable();                                                                                         \
     83   } while (0)
     84 #endif
     85 
     86 // disable warnings that show up at warning level 4
     87 // TODO: Move to build system instead
     88 #ifdef _MSC_VER
     89 #pragma warning(disable : 4201) // warning C4201: nonstandard extension used : nameless struct/union
     90 #pragma warning(disable : 4100) // warning C4100: 'Platform' : unreferenced formal parameter
     91 #pragma warning(disable : 4355) // warning C4355: 'this' : used in base member initializer list
     92 #endif
     93 
     94 using s8 = int8_t;
     95 using u8 = uint8_t;
     96 using s16 = int16_t;
     97 using u16 = uint16_t;
     98 using s32 = int32_t;
     99 using u32 = uint32_t;
    100 using s64 = int64_t;
    101 using u64 = uint64_t;
    102 
    103 // Enable use of static_assert in constexpr if
    104 template<class T>
    105 struct dependent_false : std::false_type
    106 {
    107 };
    108 template<int T>
    109 struct dependent_int_false : std::false_type
    110 {
    111 };
    112 
    113 // Architecture detection.
    114 #if defined(_MSC_VER)
    115 
    116 #if defined(_M_X64)
    117 #define CPU_ARCH_X64 1
    118 #elif defined(_M_IX86)
    119 #define CPU_ARCH_X86 1
    120 #elif defined(_M_ARM64)
    121 #define CPU_ARCH_ARM64 1
    122 #elif defined(_M_ARM)
    123 #define CPU_ARCH_ARM32 1
    124 #else
    125 #error Unknown architecture.
    126 #endif
    127 
    128 #elif defined(__GNUC__) || defined(__clang__)
    129 
    130 #if defined(__x86_64__)
    131 #define CPU_ARCH_X64 1
    132 #elif defined(__i386__)
    133 #define CPU_ARCH_X86 1
    134 #elif defined(__aarch64__)
    135 #define CPU_ARCH_ARM64 1
    136 #elif defined(__arm__)
    137 #define CPU_ARCH_ARM32 1
    138 #elif defined(__riscv) && __riscv_xlen == 64
    139 #define CPU_ARCH_RISCV64 1
    140 #else
    141 #error Unknown architecture.
    142 #endif
    143 
    144 #else
    145 
    146 #error Unknown compiler.
    147 
    148 #endif
    149 
    150 #if defined(CPU_ARCH_X64)
    151 #define CPU_ARCH_STR "x64"
    152 #elif defined(CPU_ARCH_X86)
    153 #define CPU_ARCH_STR "x86"
    154 #elif defined(CPU_ARCH_ARM32)
    155 #define CPU_ARCH_STR "arm32"
    156 #elif defined(CPU_ARCH_ARM64)
    157 #define CPU_ARCH_STR "arm64"
    158 #elif defined(CPU_ARCH_RISCV64)
    159 #define CPU_ARCH_STR "riscv64"
    160 #else
    161 #define CPU_ARCH_STR "Unknown"
    162 #endif
    163 
    164 // OS detection.
    165 #if defined(_WIN32)
    166 #define TARGET_OS_STR "Windows"
    167 #elif defined(__ANDROID__)
    168 #define TARGET_OS_STR "Android"
    169 #elif defined(__linux__)
    170 #define TARGET_OS_STR "Linux"
    171 #elif defined(__FreeBSD__)
    172 #define TARGET_OS_STR "FreeBSD"
    173 #elif defined(__APPLE__)
    174 #define TARGET_OS_STR "macOS"
    175 #else
    176 #define TARGET_OS_STR "Unknown"
    177 #endif
    178 
    179 // Host page sizes.
    180 #if defined(OVERRIDE_HOST_PAGE_SIZE)
    181 static constexpr u32 HOST_PAGE_SIZE = OVERRIDE_HOST_PAGE_SIZE;
    182 static constexpr u32 HOST_PAGE_MASK = HOST_PAGE_SIZE - 1;
    183 static constexpr u32 HOST_PAGE_SHIFT = std::bit_width(HOST_PAGE_MASK);
    184 #elif defined(__APPLE__) && defined(__aarch64__)
    185 static constexpr u32 HOST_PAGE_SIZE = 0x4000;
    186 static constexpr u32 HOST_PAGE_MASK = HOST_PAGE_SIZE - 1;
    187 static constexpr u32 HOST_PAGE_SHIFT = 14;
    188 #else
    189 static constexpr u32 HOST_PAGE_SIZE = 0x1000;
    190 static constexpr u32 HOST_PAGE_MASK = HOST_PAGE_SIZE - 1;
    191 static constexpr u32 HOST_PAGE_SHIFT = 12;
    192 #endif
    193 
    194 // Host cache line sizes.
    195 #if defined(OVERRIDE_HOST_CACHE_LINE_SIZE)
    196 static constexpr u32 HOST_CACHE_LINE_SIZE = OVERRIDE_HOST_CACHE_LINE_SIZE;
    197 #elif defined(__APPLE__) && defined(__aarch64__)
    198 static constexpr u32 HOST_CACHE_LINE_SIZE = 128; // Apple Silicon uses 128b cache lines.
    199 #else
    200 static constexpr u32 HOST_CACHE_LINE_SIZE = 64; // Everything else is 64b.
    201 #endif
    202 #define ALIGN_TO_CACHE_LINE alignas(HOST_CACHE_LINE_SIZE)
    203 
    204 // Enum class bitwise operators
    205 #define IMPLEMENT_ENUM_CLASS_BITWISE_OPERATORS(type_)                                                                  \
    206   ALWAYS_INLINE constexpr type_ operator&(type_ lhs, type_ rhs)                                                        \
    207   {                                                                                                                    \
    208     return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) &                                    \
    209                               static_cast<std::underlying_type<type_>::type>(rhs));                                    \
    210   }                                                                                                                    \
    211   ALWAYS_INLINE constexpr type_ operator|(type_ lhs, type_ rhs)                                                        \
    212   {                                                                                                                    \
    213     return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) |                                    \
    214                               static_cast<std::underlying_type<type_>::type>(rhs));                                    \
    215   }                                                                                                                    \
    216   ALWAYS_INLINE constexpr type_ operator^(type_ lhs, type_ rhs)                                                        \
    217   {                                                                                                                    \
    218     return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) ^                                    \
    219                               static_cast<std::underlying_type<type_>::type>(rhs));                                    \
    220   }                                                                                                                    \
    221   ALWAYS_INLINE constexpr type_ operator~(type_ val)                                                                   \
    222   {                                                                                                                    \
    223     return static_cast<type_>(~static_cast<std::underlying_type<type_>::type>(val));                                   \
    224   }                                                                                                                    \
    225   ALWAYS_INLINE constexpr type_& operator&=(type_& lhs, type_ rhs)                                                     \
    226   {                                                                                                                    \
    227     lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) &                                     \
    228                              static_cast<std::underlying_type<type_>::type>(rhs));                                     \
    229     return lhs;                                                                                                        \
    230   }                                                                                                                    \
    231   ALWAYS_INLINE constexpr type_& operator|=(type_& lhs, type_ rhs)                                                     \
    232   {                                                                                                                    \
    233     lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) |                                     \
    234                              static_cast<std::underlying_type<type_>::type>(rhs));                                     \
    235     return lhs;                                                                                                        \
    236   }                                                                                                                    \
    237   ALWAYS_INLINE constexpr type_& operator^=(type_& lhs, type_ rhs)                                                     \
    238   {                                                                                                                    \
    239     lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) ^                                     \
    240                              static_cast<std::underlying_type<type_>::type>(rhs));                                     \
    241     return lhs;                                                                                                        \
    242   }
    243 
    244 // Compute the address of a base type given a field offset.
    245 #define BASE_FROM_RECORD_FIELD(ptr, base_type, field) ((base_type*)(((char*)ptr) - offsetof(base_type, field)))