Defines.h (18963B)
1 /*************************************************************************************************** 2 3 Zyan Core Library (Zycore-C) 4 5 Original Author : Florian Bernd, Joel Hoener 6 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in all 15 * copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 25 ***************************************************************************************************/ 26 27 /** 28 * @file 29 * General helper and platform detection macros. 30 */ 31 32 #ifndef ZYCORE_DEFINES_H 33 #define ZYCORE_DEFINES_H 34 35 /* ============================================================================================== */ 36 /* Meta macros */ 37 /* ============================================================================================== */ 38 39 /** 40 * Concatenates two values using the stringify operator (`##`). 41 * 42 * @param x The first value. 43 * @param y The second value. 44 * 45 * @return The combined string of the given values. 46 */ 47 #define ZYAN_MACRO_CONCAT(x, y) x ## y 48 49 /** 50 * Concatenates two values using the stringify operator (`##`) and expands the value to 51 * be used in another macro. 52 * 53 * @param x The first value. 54 * @param y The second value. 55 * 56 * @return The combined string of the given values. 57 */ 58 #define ZYAN_MACRO_CONCAT_EXPAND(x, y) ZYAN_MACRO_CONCAT(x, y) 59 60 /* ============================================================================================== */ 61 /* Compiler detection */ 62 /* ============================================================================================== */ 63 64 #if defined(__clang__) 65 # define ZYAN_CLANG 66 # define ZYAN_GNUC 67 #elif defined(__ICC) || defined(__INTEL_COMPILER) 68 # define ZYAN_ICC 69 #elif defined(__GNUC__) || defined(__GNUG__) 70 # define ZYAN_GCC 71 # define ZYAN_GNUC 72 #elif defined(_MSC_VER) 73 # define ZYAN_MSVC 74 #elif defined(__BORLANDC__) 75 # define ZYAN_BORLAND 76 #else 77 # define ZYAN_UNKNOWN_COMPILER 78 #endif 79 80 /* ============================================================================================== */ 81 /* Platform detection */ 82 /* ============================================================================================== */ 83 84 #if defined(_WIN32) 85 # define ZYAN_WINDOWS 86 #elif defined(__EMSCRIPTEN__) 87 # define ZYAN_EMSCRIPTEN 88 #elif defined(__wasi__) || defined(__WASI__) 89 // via: https://reviews.llvm.org/D57155 90 # define ZYAN_WASI 91 #elif defined(__APPLE__) 92 # define ZYAN_APPLE 93 # define ZYAN_POSIX 94 #elif defined(__linux) 95 # define ZYAN_LINUX 96 # define ZYAN_POSIX 97 #elif defined(__FreeBSD__) 98 # define ZYAN_FREEBSD 99 # define ZYAN_POSIX 100 #elif defined(sun) || defined(__sun) 101 # define ZYAN_SOLARIS 102 # define ZYAN_POSIX 103 #elif defined(__unix) 104 # define ZYAN_UNIX 105 # define ZYAN_POSIX 106 #elif defined(__posix) 107 # define ZYAN_POSIX 108 #else 109 # define ZYAN_UNKNOWN_PLATFORM 110 #endif 111 112 /* ============================================================================================== */ 113 /* Kernel mode detection */ 114 /* ============================================================================================== */ 115 116 #if (defined(ZYAN_WINDOWS) && defined(_KERNEL_MODE)) || \ 117 (defined(ZYAN_APPLE) && defined(KERNEL)) || \ 118 (defined(ZYAN_LINUX) && defined(__KERNEL__)) || \ 119 (defined(__FreeBSD_kernel__)) 120 # define ZYAN_KERNEL 121 #else 122 # define ZYAN_USER 123 #endif 124 125 /* ============================================================================================== */ 126 /* Architecture detection */ 127 /* ============================================================================================== */ 128 129 #if defined(_M_AMD64) || defined(__x86_64__) 130 # define ZYAN_X64 131 #elif defined(_M_IX86) || defined(__i386__) 132 # define ZYAN_X86 133 #elif defined(_M_ARM64) || defined(__aarch64__) 134 # define ZYAN_AARCH64 135 #elif defined(_M_ARM) || defined(_M_ARMT) || defined(__arm__) || defined(__thumb__) 136 # define ZYAN_ARM 137 #elif defined(__EMSCRIPTEN__) || defined(__wasm__) || defined(__WASM__) 138 # define ZYAN_WASM 139 #elif defined(__powerpc64__) 140 # define ZYAN_PPC64 141 #elif defined(__powerpc__) 142 # define ZYAN_PPC 143 #elif defined(__riscv) && __riscv_xlen == 64 144 # define ZYAN_RISCV64 145 #else 146 # error "Unsupported architecture detected" 147 #endif 148 149 /* ============================================================================================== */ 150 /* Debug/Release detection */ 151 /* ============================================================================================== */ 152 153 #if defined(ZYAN_MSVC) || defined(ZYAN_BORLAND) 154 # ifdef _DEBUG 155 # define ZYAN_DEBUG 156 # else 157 # define ZYAN_RELEASE 158 # endif 159 #elif defined(ZYAN_GNUC) || defined(ZYAN_ICC) 160 # ifdef NDEBUG 161 # define ZYAN_RELEASE 162 # else 163 # define ZYAN_DEBUG 164 # endif 165 #else 166 # define ZYAN_RELEASE 167 #endif 168 169 /* ============================================================================================== */ 170 /* Deprecation hint */ 171 /* ============================================================================================== */ 172 173 #if defined(ZYAN_GCC) || defined(ZYAN_CLANG) 174 # define ZYAN_DEPRECATED __attribute__((__deprecated__)) 175 #elif defined(ZYAN_MSVC) 176 # define ZYAN_DEPRECATED __declspec(deprecated) 177 #else 178 # define ZYAN_DEPRECATED 179 #endif 180 181 /* ============================================================================================== */ 182 /* Generic DLL import/export helpers */ 183 /* ============================================================================================== */ 184 185 #if defined(ZYAN_MSVC) 186 # define ZYAN_DLLEXPORT __declspec(dllexport) 187 # define ZYAN_DLLIMPORT __declspec(dllimport) 188 #else 189 # define ZYAN_DLLEXPORT 190 # define ZYAN_DLLIMPORT 191 #endif 192 193 /* ============================================================================================== */ 194 /* Zycore dll{export,import} */ 195 /* ============================================================================================== */ 196 197 // This is a cut-down version of what CMake's `GenerateExportHeader` would usually generate. To 198 // simplify builds without CMake, we define these things manually instead of relying on CMake 199 // to generate the header. 200 // 201 // For static builds, our CMakeList will define `ZYCORE_STATIC_BUILD`. For shared library builds, 202 // our CMake will define `ZYCORE_SHOULD_EXPORT` depending on whether the target is being imported or 203 // exported. If CMake isn't used, users can manually define these to fit their use-case. 204 205 // Backward compatibility: CMake would previously generate these variables names. However, because 206 // they have pretty cryptic names, we renamed them when we got rid of `GenerateExportHeader`. For 207 // backward compatibility for users that don't use CMake and previously manually defined these, we 208 // translate the old defines here and print a warning. 209 #if defined(ZYCORE_STATIC_DEFINE) 210 # pragma message("ZYCORE_STATIC_DEFINE was renamed to ZYCORE_STATIC_BUILD.") 211 # define ZYCORE_STATIC_BUILD 212 #endif 213 #if defined(Zycore_EXPORTS) 214 # pragma message("Zycore_EXPORTS was renamed to ZYCORE_SHOULD_EXPORT.") 215 # define ZYCORE_SHOULD_EXPORT 216 #endif 217 218 /** 219 * Symbol is exported in shared library builds. 220 */ 221 #if defined(ZYCORE_STATIC_BUILD) 222 # define ZYCORE_EXPORT 223 #else 224 # if defined(ZYCORE_SHOULD_EXPORT) 225 # define ZYCORE_EXPORT ZYAN_DLLEXPORT 226 # else 227 # define ZYCORE_EXPORT ZYAN_DLLIMPORT 228 # endif 229 #endif 230 231 /** 232 * Symbol is not exported and for internal use only. 233 */ 234 #define ZYCORE_NO_EXPORT 235 236 /* ============================================================================================== */ 237 /* Misc compatibility macros */ 238 /* ============================================================================================== */ 239 240 #if defined(ZYAN_CLANG) 241 # define ZYAN_NO_SANITIZE(what) __attribute__((no_sanitize(what))) 242 #else 243 # define ZYAN_NO_SANITIZE(what) 244 #endif 245 246 #if defined(ZYAN_MSVC) || defined(ZYAN_BORLAND) 247 # define ZYAN_INLINE __inline 248 #else 249 # define ZYAN_INLINE static inline 250 #endif 251 252 #if defined(ZYAN_MSVC) 253 # define ZYAN_NOINLINE __declspec(noinline) 254 #elif defined(ZYAN_GCC) || defined(ZYAN_CLANG) 255 # define ZYAN_NOINLINE __attribute__((noinline)) 256 #else 257 # define ZYAN_NOINLINE 258 #endif 259 260 /* ============================================================================================== */ 261 /* Debugging and optimization macros */ 262 /* ============================================================================================== */ 263 264 /** 265 * Runtime debug assertion. 266 */ 267 #if defined(ZYAN_NO_LIBC) 268 # define ZYAN_ASSERT(condition) (void)(condition) 269 #elif defined(ZYAN_WINDOWS) && defined(ZYAN_KERNEL) 270 # include <wdm.h> 271 # define ZYAN_ASSERT(condition) NT_ASSERT(condition) 272 #else 273 # include <assert.h> 274 # define ZYAN_ASSERT(condition) assert(condition) 275 #endif 276 277 /** 278 * Compiler-time assertion. 279 */ 280 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__cplusplus) 281 # define ZYAN_STATIC_ASSERT(x) _Static_assert(x, #x) 282 #elif (defined(__cplusplus) && __cplusplus >= 201103L) || \ 283 (defined(__cplusplus) && defined (_MSC_VER) && (_MSC_VER >= 1600)) || \ 284 (defined (_MSC_VER) && (_MSC_VER >= 1800)) 285 # define ZYAN_STATIC_ASSERT(x) static_assert(x, #x) 286 #else 287 # define ZYAN_STATIC_ASSERT(x) \ 288 typedef int ZYAN_MACRO_CONCAT_EXPAND(ZYAN_SASSERT_, __COUNTER__) [(x) ? 1 : -1] 289 #endif 290 291 /** 292 * Marks the current code path as unreachable. 293 */ 294 #if defined(ZYAN_RELEASE) 295 # if defined(ZYAN_CLANG) // GCC eagerly evals && RHS, we have to use nested ifs. 296 # if __has_builtin(__builtin_unreachable) 297 # define ZYAN_UNREACHABLE __builtin_unreachable() 298 # else 299 # define ZYAN_UNREACHABLE for(;;) 300 # endif 301 # elif defined(ZYAN_GCC) && ((__GNUC__ == 4 && __GNUC_MINOR__ > 4) || __GNUC__ > 4) 302 # define ZYAN_UNREACHABLE __builtin_unreachable() 303 # elif defined(ZYAN_ICC) 304 # ifdef ZYAN_WINDOWS 305 # include <stdlib.h> // "missing return statement" workaround 306 # define ZYAN_UNREACHABLE __assume(0); (void)abort() 307 # else 308 # define ZYAN_UNREACHABLE __builtin_unreachable() 309 # endif 310 # elif defined(ZYAN_MSVC) 311 # define ZYAN_UNREACHABLE __assume(0) 312 # else 313 # define ZYAN_UNREACHABLE for(;;) 314 # endif 315 #elif defined(ZYAN_NO_LIBC) 316 # define ZYAN_UNREACHABLE for(;;) 317 #elif defined(ZYAN_WINDOWS) && defined(ZYAN_KERNEL) 318 # define ZYAN_UNREACHABLE { __fastfail(0); for(;;){} } 319 #else 320 # include <stdlib.h> 321 # define ZYAN_UNREACHABLE { assert(0); abort(); } 322 #endif 323 324 /* ============================================================================================== */ 325 /* Utils */ 326 /* ============================================================================================== */ 327 328 /* ---------------------------------------------------------------------------------------------- */ 329 /* General purpose */ 330 /* ---------------------------------------------------------------------------------------------- */ 331 332 /** 333 * Marks the specified parameter as unused. 334 * 335 * @param x The name of the unused parameter. 336 */ 337 #define ZYAN_UNUSED(x) (void)(x) 338 339 /** 340 * Intentional fallthrough. 341 */ 342 #if defined(ZYAN_GCC) && __GNUC__ >= 7 343 # define ZYAN_FALLTHROUGH ; __attribute__((__fallthrough__)) 344 #else 345 # define ZYAN_FALLTHROUGH 346 #endif 347 348 /** 349 * Declares a bitfield. 350 * 351 * @param x The size (in bits) of the bitfield. 352 */ 353 #define ZYAN_BITFIELD(x) : x 354 355 /** 356 * Marks functions that require libc (cannot be used with `ZYAN_NO_LIBC`). 357 */ 358 #define ZYAN_REQUIRES_LIBC 359 360 /** 361 * Decorator for `printf`-style functions. 362 * 363 * @param format_index The 1-based index of the format string parameter. 364 * @param first_to_check The 1-based index of the format arguments parameter. 365 */ 366 #if defined(__RESHARPER__) 367 # define ZYAN_PRINTF_ATTR(format_index, first_to_check) \ 368 [[gnu::format(printf, format_index, first_to_check)]] 369 #elif defined(ZYAN_GCC) 370 # define ZYAN_PRINTF_ATTR(format_index, first_to_check) \ 371 __attribute__((format(printf, format_index, first_to_check))) 372 #else 373 # define ZYAN_PRINTF_ATTR(format_index, first_to_check) 374 #endif 375 376 /** 377 * Decorator for `wprintf`-style functions. 378 * 379 * @param format_index The 1-based index of the format string parameter. 380 * @param first_to_check The 1-based index of the format arguments parameter. 381 */ 382 #if defined(__RESHARPER__) 383 # define ZYAN_WPRINTF_ATTR(format_index, first_to_check) \ 384 [[rscpp::format(wprintf, format_index, first_to_check)]] 385 #else 386 # define ZYAN_WPRINTF_ATTR(format_index, first_to_check) 387 #endif 388 389 /* ---------------------------------------------------------------------------------------------- */ 390 /* Arrays */ 391 /* ---------------------------------------------------------------------------------------------- */ 392 393 /** 394 * Returns the length (number of elements) of an array. 395 * 396 * @param a The name of the array. 397 * 398 * @return The number of elements of the given array. 399 */ 400 #define ZYAN_ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) 401 402 /* ---------------------------------------------------------------------------------------------- */ 403 /* Arithmetic */ 404 /* ---------------------------------------------------------------------------------------------- */ 405 406 /** 407 * Returns the smaller value of `a` or `b`. 408 * 409 * @param a The first value. 410 * @param b The second value. 411 * 412 * @return The smaller value of `a` or `b`. 413 */ 414 #define ZYAN_MIN(a, b) (((a) < (b)) ? (a) : (b)) 415 416 /** 417 * Returns the bigger value of `a` or `b`. 418 * 419 * @param a The first value. 420 * @param b The second value. 421 * 422 * @return The bigger value of `a` or `b`. 423 */ 424 #define ZYAN_MAX(a, b) (((a) > (b)) ? (a) : (b)) 425 426 /** 427 * Returns the absolute value of `a`. 428 * 429 * @param a The value. 430 * 431 * @return The absolute value of `a`. 432 */ 433 #define ZYAN_ABS(a) (((a) < 0) ? -(a) : (a)) 434 435 /** 436 * Checks, if the given value is a power of 2. 437 * 438 * @param x The value. 439 * 440 * @return `ZYAN_TRUE`, if the given value is a power of 2 or `ZYAN_FALSE`, if not. 441 * 442 * Note that this macro always returns `ZYAN_TRUE` for `x == 0`. 443 */ 444 #define ZYAN_IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0) 445 446 /** 447 * Checks, if the given value is properly aligned. 448 * 449 * Note that this macro only works for powers of 2. 450 */ 451 #define ZYAN_IS_ALIGNED_TO(x, align) (((x) & ((align) - 1)) == 0) 452 453 /** 454 * Aligns the value to the nearest given alignment boundary (by rounding it up). 455 * 456 * @param x The value. 457 * @param align The desired alignment. 458 * 459 * @return The aligned value. 460 * 461 * Note that this macro only works for powers of 2. 462 */ 463 #define ZYAN_ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1)) 464 465 /** 466 * Aligns the value to the nearest given alignment boundary (by rounding it down). 467 * 468 * @param x The value. 469 * @param align The desired alignment. 470 * 471 * @return The aligned value. 472 * 473 * Note that this macro only works for powers of 2. 474 */ 475 #define ZYAN_ALIGN_DOWN(x, align) (((x) - 1) & ~((align) - 1)) 476 477 /* ---------------------------------------------------------------------------------------------- */ 478 /* Bit operations */ 479 /* ---------------------------------------------------------------------------------------------- */ 480 481 /* 482 * Checks, if the bit at index `b` is required to present the ordinal value `n`. 483 * 484 * @param n The ordinal value. 485 * @param b The bit index. 486 * 487 * @return `ZYAN_TRUE`, if the bit at index `b` is required to present the ordinal value `n` or 488 * `ZYAN_FALSE`, if not. 489 * 490 * Note that this macro always returns `ZYAN_FALSE` for `n == 0`. 491 */ 492 #define ZYAN_NEEDS_BIT(n, b) (((unsigned long)(n) >> (b)) > 0) 493 494 /* 495 * Returns the number of bits required to represent the ordinal value `n`. 496 * 497 * @param n The ordinal value. 498 * 499 * @return The number of bits required to represent the ordinal value `n`. 500 * 501 * Note that this macro returns `0` for `n == 0`. 502 */ 503 #define ZYAN_BITS_TO_REPRESENT(n) \ 504 ( \ 505 ZYAN_NEEDS_BIT(n, 0) + ZYAN_NEEDS_BIT(n, 1) + \ 506 ZYAN_NEEDS_BIT(n, 2) + ZYAN_NEEDS_BIT(n, 3) + \ 507 ZYAN_NEEDS_BIT(n, 4) + ZYAN_NEEDS_BIT(n, 5) + \ 508 ZYAN_NEEDS_BIT(n, 6) + ZYAN_NEEDS_BIT(n, 7) + \ 509 ZYAN_NEEDS_BIT(n, 8) + ZYAN_NEEDS_BIT(n, 9) + \ 510 ZYAN_NEEDS_BIT(n, 10) + ZYAN_NEEDS_BIT(n, 11) + \ 511 ZYAN_NEEDS_BIT(n, 12) + ZYAN_NEEDS_BIT(n, 13) + \ 512 ZYAN_NEEDS_BIT(n, 14) + ZYAN_NEEDS_BIT(n, 15) + \ 513 ZYAN_NEEDS_BIT(n, 16) + ZYAN_NEEDS_BIT(n, 17) + \ 514 ZYAN_NEEDS_BIT(n, 18) + ZYAN_NEEDS_BIT(n, 19) + \ 515 ZYAN_NEEDS_BIT(n, 20) + ZYAN_NEEDS_BIT(n, 21) + \ 516 ZYAN_NEEDS_BIT(n, 22) + ZYAN_NEEDS_BIT(n, 23) + \ 517 ZYAN_NEEDS_BIT(n, 24) + ZYAN_NEEDS_BIT(n, 25) + \ 518 ZYAN_NEEDS_BIT(n, 26) + ZYAN_NEEDS_BIT(n, 27) + \ 519 ZYAN_NEEDS_BIT(n, 28) + ZYAN_NEEDS_BIT(n, 29) + \ 520 ZYAN_NEEDS_BIT(n, 30) + ZYAN_NEEDS_BIT(n, 31) \ 521 ) 522 523 /* ---------------------------------------------------------------------------------------------- */ 524 525 /* ============================================================================================== */ 526 527 #endif /* ZYCORE_DEFINES_H */