Defines.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. #pragma once
  2. #include <cassert>
  3. #include <cinttypes>
  4. #include <climits>
  5. #include <cstdint>
  6. #include <cstdio>
  7. #include <cstdlib>
  8. #include <cstdarg>
  9. #ifndef GP_NO_MALLOC_FREE
  10. # include <cstring>
  11. #else
  12. # include <cstddef>
  13. #endif
  14. #include <exception>
  15. #include <type_traits>
  16. #include <mutex>
  17. #ifdef NDEBUG
  18. # define GP_DEBUG 0
  19. #else
  20. # define GP_DEBUG 1
  21. #endif
  22. #ifdef _WIN32
  23. # define GP_PLATFORM_WINDOWS 1
  24. # define GP_PLATFORM_LINUX 0
  25. # define GP_PLATFORM_MACOS 0
  26. # define GP_PLATFORM_IOS 0
  27. # define GP_PLATFORM_ANDROID 0
  28. #elif defined(__APPLE__)
  29. # include "TargetConditionals.h"
  30. # if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
  31. # define GP_PLATFORM_WINDOWS 0
  32. # define GP_PLATFORM_LINUX 0
  33. # define GP_PLATFORM_MACOS 0
  34. # define GP_PLATFORM_IOS 1
  35. # define GP_PLATFORM_ANDROID 0
  36. # elif TARGET_OS_MAC
  37. # define GP_PLATFORM_WINDOWS 0
  38. # define GP_PLATFORM_LINUX 0
  39. # define GP_PLATFORM_MACOS 1
  40. # define GP_PLATFORM_IOS 0
  41. # define GP_PLATFORM_ANDROID 0
  42. # endif
  43. #elif defined(__ANDROID__)
  44. # define GP_PLATFORM_WINDOWS 0
  45. # define GP_PLATFORM_LINUX 0
  46. # define GP_PLATFORM_MACOS 0
  47. # define GP_PLATFORM_IOS 0
  48. # define GP_PLATFORM_ANDROID 1
  49. #elif defined(__linux__)
  50. # define GP_PLATFORM_WINDOWS 0
  51. # define GP_PLATFORM_LINUX 1
  52. # define GP_PLATFORM_MACOS 0
  53. # define GP_PLATFORM_IOS 0
  54. # define GP_PLATFORM_ANDROID 0
  55. #else
  56. # error "Unsupported platform"
  57. #endif
  58. #if GP_PLATFORM_WINDOWS
  59. # ifndef GP_NO_MALLOC_FREE
  60. # include "malloc.h"
  61. # endif
  62. # include <intrin.h>
  63. #elif GP_PLATFORM_LINUX
  64. # include <alloca.h>
  65. # include <signal.h>
  66. # define _alloca alloca
  67. #endif
  68. #if defined(__aarch64__)
  69. # define GP_ARCH_AARCH64 1
  70. # define GP_ARCH_X86_64 0
  71. #elif defined(__x86_64__) || defined(_M_X64)
  72. # define GP_ARCH__X86_64 1
  73. # define GP_ARCH_AARCH64 0
  74. #endif
  75. #if defined(_MSC_VER)
  76. # define GP_COMPILER_MSC 1
  77. # define GP_COMPILER_GNUC 0
  78. # define GP_ASAN_ENABLED 0
  79. #endif
  80. #if defined(__GNUC__)
  81. # define GP_COMPILER_MSC 0
  82. # define GP_COMPILER_GNUC 1
  83. # ifdef __SANITIZE_ADDRESS__
  84. # define GP_ASAN_ENABLED __SANITIZE_ADDRESS__
  85. # else
  86. # define GP_ASAN_ENABLED 0
  87. # endif
  88. #endif
  89. #if GP_COMPILER_MSC
  90. # define GP_PRETTY_FUNCTION __FUNCSIG__
  91. # define GP_ATTRIBUTE(...)
  92. # define GP_DECLSPEC(...) __declspec(__VA_ARGS__)
  93. # define GP_IGNOREWARNING_MSC_PUSH __pragma(warning(push))
  94. # define GP_IGNOREWARNING_MSC_POP __pragma(warning(pop))
  95. # define GP_IGNOREWARNING_MSC(w) __pragma(warning(disable : w))
  96. # define GP_IGNOREWARNING_MSC_WITH_PUSH(w) \
  97. GP_IGNOREWARNING_MSC_PUSH \
  98. GP_IGNOREWARNING_MSC(w)
  99. # define GP_IGNOREWARNING_GNUC_PUSH
  100. # define GP_IGNOREWARNING_GNUC_POP
  101. # define GP_IGNOREWARNING_GNUC(w)
  102. # define GP_IGNOREWARNING_GNUC_WITH_PUSH(w)
  103. #elif GP_COMPILER_GNUC
  104. # define GP_PRETTY_FUNCTION __PRETTY_FUNCTION__
  105. # define GP_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
  106. # define GP_DECLSPEC(...)
  107. # define GP_IGNOREWARNING_MSC_PUSH
  108. # define GP_IGNOREWARNING_MSC_POP
  109. # define GP_IGNOREWARNING_MSC(w)
  110. # define GP_IGNOREWARNING_MSC_WITH_PUSH(w)
  111. # define GP_IGNOREWARNING_GNUC_PUSH _Pragma("GCC diagnostic push")
  112. # define GP_IGNOREWARNING_GNUC_POP _Pragma("GCC diagnostic pop")
  113. # define GP_IGNOREWARNING_GNUC_INTERNAL(str) _Pragma(# str)
  114. # define GP_IGNOREWARNING_GNUC(w) GP_IGNOREWARNING_GNUC_INTERNAL(GCC diagnostic ignored w)
  115. # define GP_IGNOREWARNING_GNUC_WITH_PUSH(w) \
  116. GCC_IGNOREWARNING_GNUC_PUSH \
  117. GCC_IGNOREWARNING_GNUC(w)
  118. #else
  119. # error Unsupported compiler
  120. #endif
  121. #ifdef GP_EXPORT
  122. # define GP_API GP_DECLSPEC(dllexport) GP_ATTRIBUTE(visibility("default"))
  123. #else
  124. # define GP_API GP_DECLSPEC(dllimport)
  125. #endif
  126. #define GP_NOINLINE GP_ATTRIBUTE(noinline) GP_DECLSPEC(noinline)
  127. #define GP_DEPRECATED(msg) GP_ATTRIBUTE(deprecated(msg)) GP_DECLSPEC(deprecated(msg))
  128. namespace gameplay
  129. {
  130. template <typename T>
  131. constexpr T align(T x, size_t alignment)
  132. {
  133. return (T)(((size_t)x + alignment - 1) / alignment * alignment);
  134. }
  135. template <typename T>
  136. T* align(T* x, size_t alignment)
  137. {
  138. return (T*)(((size_t)x + alignment - 1) / alignment * alignment);
  139. }
  140. #define GP_ALIGN(x, alignment) gameplay::align(x, alignment)
  141. template <typename T>
  142. constexpr T aligned_size(const T& size, uint32_t alignment)
  143. {
  144. return ((size + alignment - 1) / alignment) * alignment;
  145. }
  146. #define GP_ALIGNED_SIZE(size, alignment) gameplay::aligned_size(size, alignment)
  147. #define GP_ALIGN_AS(T) alignas(T)
  148. template <typename T, size_t N>
  149. constexpr size_t count_of(T const (&)[N])
  150. {
  151. return N;
  152. }
  153. #define GP_COUNTOF(a) gameplay::count_of(a)
  154. template <typename T, uint32_t N>
  155. constexpr uint32_t count_of32(T const (&)[N])
  156. {
  157. return N;
  158. }
  159. #define GP_COUNTOF32(a) gameplay::count_of32(a)
  160. template <typename T, typename U>
  161. constexpr uint32_t offset_of(U T::*member)
  162. {
  163. return (uint32_t)((char*)&((T*)nullptr->*member) - (char*)nullptr);
  164. }
  165. #define GP_OFFSETOF(a) gameplay::offset_of(&a)
  166. #if GP_COMPILER_MSC
  167. # define GP_ALIGN_OF(T) __alignof(T)
  168. #elif GP_COMPILER_GNUC
  169. # define GP_ALIGN_OF(T) __alignof__(T)
  170. #else
  171. # error Unsupported compiler
  172. #endif
  173. inline bool assert_handler(const char* condition, const char* file, const char* func, int32_t line, const char* fmt = nullptr, ...)
  174. {
  175. static std::mutex m;
  176. std::lock_guard<std::mutex> g(m);
  177. if (fmt != nullptr)
  178. {
  179. fprintf(stderr, "%s:%s():%" PRId32 ": Assertion (%s) failed: ", file, func, line, condition);
  180. va_list args;
  181. va_start(args, fmt);
  182. vfprintf(stderr, fmt, args);
  183. va_end(args);
  184. fputc('\n', stderr);
  185. }
  186. else
  187. {
  188. fprintf(stderr, "%s:%" PRId32 ":%s(): Assertion (%s) failed.\n", file, line, func, condition);
  189. }
  190. return true;
  191. }
  192. #define GP_STACK_ALLOC(T, number) \
  193. gameplay::align<T>(((number) ? (T*)_alloca((number) * sizeof(T) + alignof(T)) : nullptr), alignof(T))
  194. #define GP_MALLOC(size) std::malloc(size)
  195. #define GP_FREE(ptr) std::free(ptr)
  196. #define GP_STRINGIFY_INTERNAL(x) #x
  197. #define GP_STRINGIFY(x) GP_STRINGIFY_INTERNAL(x)
  198. constexpr uint64_t GP_FNV_BASIS = 14695981039346656037ull;
  199. constexpr uint64_t GP_FNV_PRIME = 1099511628211ull;
  200. constexpr uint64_t fnv1a_hash(const char* str, std::size_t n, uint64_t hash = GP_FNV_BASIS)
  201. {
  202. return n > 0 ? fnv1a_hash(str + 1, n - 1, (hash ^ *str) * GP_FNV_PRIME) : hash;
  203. }
  204. template <std::size_t N>
  205. constexpr uint64_t fnv1a_hash(const char (&array)[N])
  206. {
  207. return fnv1aHash(&array[0], N - 1);
  208. }
  209. inline uint64_t hash_string(const char* str, uint64_t hash = GP_FNV_BASIS)
  210. {
  211. for (uint32_t i = 0; str[i] != 0; ++i)
  212. {
  213. hash ^= static_cast<unsigned char>(str[i]);
  214. hash *= GP_FNV_PRIME;
  215. }
  216. return hash;
  217. }
  218. inline uint64_t hash_buffer(const void* buffer, size_t length, uint64_t hash = GP_FNV_BASIS)
  219. {
  220. const char* ptr = static_cast<const char*>(buffer);
  221. for (size_t i = 0; i < length; ++i)
  222. {
  223. hash ^= static_cast<unsigned char>(ptr[i]);
  224. hash *= GP_FNV_PRIME;
  225. }
  226. return hash;
  227. }
  228. template <class T>
  229. constexpr uint64_t hash_scalar(const T& type, uint64_t hash = GP_FNV_BASIS)
  230. {
  231. static_assert(std::is_scalar<T>::value, "Unsupported type for hashing");
  232. return hash_buffer(reinterpret_cast<const char*>(std::addressof(type)), sizeof(type), hash);
  233. }
  234. #if defined(__CUDACC__)
  235. # define GP_HASH_STRING(str) std::integral_constant<uint64_t, gameplay::fnv1a_hash(str)>::value
  236. #else
  237. # define GP_HASH_STRING(str) \
  238. GP_IGNOREWARNING_MSC_WITH_PUSH(4307) \
  239. std::integral_constant<uint64_t, gameplay::fnv1a_hash(str)>::value GP_IGNOREWARNING_MSC_POP
  240. #endif
  241. #define GP_HASH_TYPE(T) GP_HASH_STRING(GP_STRINGIFY(T))
  242. }
  243. #if GP_PLATFORM_LINUX
  244. # define GP_BREAK_POINT() ::raise(SIGTRAP)
  245. #elif GP_PLATFORM_WINDOWS
  246. # define GP_BREAK_POINT() ::__debugbreak()
  247. #else
  248. # error "Unsupported platform"
  249. #endif
  250. #ifndef GP_CHECK
  251. # define GP_CHECK(cond, ...) \
  252. ![&](const char* funcname__, ...) GP_NOINLINE { \
  253. return ::gameplay::assert_handler(#cond, __FILE__, funcname__, __LINE__, ##__VA_ARGS__); \
  254. }
  255. #endif
  256. #ifndef GP_ASSERT
  257. # if GP_DEBUG
  258. # define GP_ASSERT(cond, ...) assert(cond)
  259. # else
  260. # define GP_ASSERT
  261. # endif
  262. #endif
  263. #define GP_ASSERT_STRUCTS_MATCH(A, B) \
  264. static_assert(sizeof(A) == sizeof(B), "Size mismatch between " #A " and " #B "."); \
  265. static_assert(alignof(A) == alignof(B), "Alignment mismatch between " #A " and " #B ".")
  266. #define GP_ASSERT_MEMBERS_MATCH(A, a, B, b) \
  267. static_assert( \
  268. offsetof(A, a) == offsetof(B, b), "Offset mismatch between members " #a " of " #A " and " #b " of " #B ".")
  269. #define GP_SAFE_DELETE(ptr) \
  270. { \
  271. delete ptr; \
  272. ptr = nullptr; \
  273. }
  274. #define GP_SAFE_DELETE_ARRAY(ptr) \
  275. { \
  276. delete[] ptr; \
  277. ptr = nullptr; \
  278. }
  279. #define GP_UINT16_MAX UINT16_MAX
  280. #define GP_UINT32_MAX UINT32_MAX
  281. #define GP_UINT64_MAX UINT64_MAX
  282. #define GP_ULLONG_MAX ULLONG_MAX
  283. #define GP_USHRT_MAX USHRT_MAX
  284. #define GP_FLOAT_MAX 3.402823466e+38F
  285. #define GP_MIN(a, b) (((a) < (b)) ? (a) : (b))
  286. #define GP_MAX(a, b) (((a) > (b)) ? (a) : (b))
  287. #define GP_CLAMP(x, lo, hi) (((x) < (lo)) ? (lo) : (((x) > (hi)) ? (hi) : (x)))
  288. #define GP_ROUNDUP(value, to) ((((value) + (to)-1) / (to)) * (to))
  289. template <class... Args>
  290. void GP_UNUSED(Args&&...) {}