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(__NetBSD__) 101 # define ZYAN_NETBSD 102 # define ZYAN_POSIX 103 #elif defined(sun) || defined(__sun) 104 # define ZYAN_SOLARIS 105 # define ZYAN_POSIX 106 #elif defined(__unix) || defined(__unix__) 107 # define ZYAN_UNIX 108 # define ZYAN_POSIX 109 #elif defined(__posix) 110 # define ZYAN_POSIX 111 #else 112 # define ZYAN_UNKNOWN_PLATFORM 113 #endif 114 115 /* ============================================================================================== */ 116 /* Kernel mode detection */ 117 /* ============================================================================================== */ 118 119 #if (defined(ZYAN_WINDOWS) && defined(_KERNEL_MODE)) || \ 120 (defined(ZYAN_APPLE) && defined(KERNEL)) || \ 121 (defined(ZYAN_LINUX) && defined(__KERNEL__)) || \ 122 (defined(__FreeBSD_kernel__)) 123 # define ZYAN_KERNEL 124 #else 125 # define ZYAN_USER 126 #endif 127 128 /* ============================================================================================== */ 129 /* Architecture detection */ 130 /* ============================================================================================== */ 131 132 #if defined(_M_AMD64) || defined(__x86_64__) 133 # define ZYAN_X64 134 #elif defined(_M_IX86) || defined(__i386__) 135 # define ZYAN_X86 136 #elif defined(_M_ARM64) || defined(__aarch64__) 137 # define ZYAN_AARCH64 138 #elif defined(_M_ARM) || defined(_M_ARMT) || defined(__arm__) || defined(__thumb__) 139 # define ZYAN_ARM 140 #elif defined(__EMSCRIPTEN__) || defined(__wasm__) || defined(__WASM__) 141 # define ZYAN_WASM 142 #elif defined(__loongarch__) 143 # define ZYAN_LOONGARCH 144 #elif defined(__powerpc64__) 145 # define ZYAN_PPC64 146 #elif defined(__powerpc__) 147 # define ZYAN_PPC 148 #elif defined(__riscv) && __riscv_xlen == 64 149 # define ZYAN_RISCV64 150 #else 151 # error "Unsupported architecture detected" 152 #endif 153 154 /* ============================================================================================== */ 155 /* Debug/Release detection */ 156 /* ============================================================================================== */ 157 158 #if defined(ZYAN_MSVC) || defined(ZYAN_BORLAND) 159 # ifdef _DEBUG 160 # define ZYAN_DEBUG 161 # else 162 # define ZYAN_RELEASE 163 # endif 164 #elif defined(ZYAN_GNUC) || defined(ZYAN_ICC) 165 # ifdef NDEBUG 166 # define ZYAN_RELEASE 167 # else 168 # define ZYAN_DEBUG 169 # endif 170 #else 171 # define ZYAN_RELEASE 172 #endif 173 174 /* ============================================================================================== */ 175 /* Deprecation hint */ 176 /* ============================================================================================== */ 177 178 #if defined(ZYAN_GCC) || defined(ZYAN_CLANG) 179 # define ZYAN_DEPRECATED __attribute__((__deprecated__)) 180 #elif defined(ZYAN_MSVC) 181 # define ZYAN_DEPRECATED __declspec(deprecated) 182 #else 183 # define ZYAN_DEPRECATED 184 #endif 185 186 /* ============================================================================================== */ 187 /* Generic DLL import/export helpers */ 188 /* ============================================================================================== */ 189 190 #if defined(ZYAN_MSVC) 191 # define ZYAN_DLLEXPORT __declspec(dllexport) 192 # define ZYAN_DLLIMPORT __declspec(dllimport) 193 #else 194 # define ZYAN_DLLEXPORT 195 # define ZYAN_DLLIMPORT 196 #endif 197 198 /* ============================================================================================== */ 199 /* Zycore dll{export,import} */ 200 /* ============================================================================================== */ 201 202 // This is a cut-down version of what CMake's `GenerateExportHeader` would usually generate. To 203 // simplify builds without CMake, we define these things manually instead of relying on CMake 204 // to generate the header. 205 // 206 // For static builds, our CMakeList will define `ZYCORE_STATIC_BUILD`. For shared library builds, 207 // our CMake will define `ZYCORE_SHOULD_EXPORT` depending on whether the target is being imported or 208 // exported. If CMake isn't used, users can manually define these to fit their use-case. 209 210 // Backward compatibility: CMake would previously generate these variables names. However, because 211 // they have pretty cryptic names, we renamed them when we got rid of `GenerateExportHeader`. For 212 // backward compatibility for users that don't use CMake and previously manually defined these, we 213 // translate the old defines here and print a warning. 214 #if defined(ZYCORE_STATIC_DEFINE) 215 # pragma message("ZYCORE_STATIC_DEFINE was renamed to ZYCORE_STATIC_BUILD.") 216 # define ZYCORE_STATIC_BUILD 217 #endif 218 #if defined(Zycore_EXPORTS) 219 # pragma message("Zycore_EXPORTS was renamed to ZYCORE_SHOULD_EXPORT.") 220 # define ZYCORE_SHOULD_EXPORT 221 #endif 222 223 /** 224 * Symbol is exported in shared library builds. 225 */ 226 #if defined(ZYCORE_STATIC_BUILD) 227 # define ZYCORE_EXPORT 228 #else 229 # if defined(ZYCORE_SHOULD_EXPORT) 230 # define ZYCORE_EXPORT ZYAN_DLLEXPORT 231 # else 232 # define ZYCORE_EXPORT ZYAN_DLLIMPORT 233 # endif 234 #endif 235 236 /** 237 * Symbol is not exported and for internal use only. 238 */ 239 #define ZYCORE_NO_EXPORT 240 241 /* ============================================================================================== */ 242 /* Misc compatibility macros */ 243 /* ============================================================================================== */ 244 245 #if defined(ZYAN_CLANG) 246 # define ZYAN_NO_SANITIZE(what) __attribute__((no_sanitize(what))) 247 #else 248 # define ZYAN_NO_SANITIZE(what) 249 #endif 250 251 #if defined(ZYAN_MSVC) || defined(ZYAN_BORLAND) 252 # define ZYAN_INLINE __inline 253 #else 254 # define ZYAN_INLINE static inline 255 #endif 256 257 #if defined(ZYAN_MSVC) 258 # define ZYAN_NOINLINE __declspec(noinline) 259 #elif defined(ZYAN_GCC) || defined(ZYAN_CLANG) 260 # define ZYAN_NOINLINE __attribute__((noinline)) 261 #else 262 # define ZYAN_NOINLINE 263 #endif 264 265 /* ============================================================================================== */ 266 /* Debugging and optimization macros */ 267 /* ============================================================================================== */ 268 269 /** 270 * Runtime debug assertion. 271 */ 272 #if defined(ZYAN_NO_LIBC) 273 # define ZYAN_ASSERT(condition) (void)(condition) 274 #elif defined(ZYAN_WINDOWS) && defined(ZYAN_KERNEL) 275 # include <wdm.h> 276 # define ZYAN_ASSERT(condition) NT_ASSERT(condition) 277 #else 278 # include <assert.h> 279 # define ZYAN_ASSERT(condition) assert(condition) 280 #endif 281 282 /** 283 * Compiler-time assertion. 284 */ 285 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__cplusplus) 286 # define ZYAN_STATIC_ASSERT(x) _Static_assert(x, #x) 287 #elif (defined(__cplusplus) && __cplusplus >= 201103L) || \ 288 (defined(__cplusplus) && defined (_MSC_VER) && (_MSC_VER >= 1600)) || \ 289 (defined (_MSC_VER) && (_MSC_VER >= 1800)) 290 # define ZYAN_STATIC_ASSERT(x) static_assert(x, #x) 291 #else 292 # define ZYAN_STATIC_ASSERT(x) \ 293 typedef int ZYAN_MACRO_CONCAT_EXPAND(ZYAN_SASSERT_, __COUNTER__) [(x) ? 1 : -1] 294 #endif 295 296 /** 297 * Marks the current code path as unreachable. 298 */ 299 #if defined(ZYAN_RELEASE) 300 # if defined(ZYAN_CLANG) // GCC eagerly evals && RHS, we have to use nested ifs. 301 # if __has_builtin(__builtin_unreachable) 302 # define ZYAN_UNREACHABLE __builtin_unreachable() 303 # else 304 # define ZYAN_UNREACHABLE for(;;) 305 # endif 306 # elif defined(ZYAN_GCC) && ((__GNUC__ == 4 && __GNUC_MINOR__ > 4) || __GNUC__ > 4) 307 # define ZYAN_UNREACHABLE __builtin_unreachable() 308 # elif defined(ZYAN_ICC) 309 # ifdef ZYAN_WINDOWS 310 # include <stdlib.h> // "missing return statement" workaround 311 # define ZYAN_UNREACHABLE __assume(0); (void)abort() 312 # else 313 # define ZYAN_UNREACHABLE __builtin_unreachable() 314 # endif 315 # elif defined(ZYAN_MSVC) 316 # define ZYAN_UNREACHABLE __assume(0) 317 # else 318 # define ZYAN_UNREACHABLE for(;;) 319 # endif 320 #elif defined(ZYAN_NO_LIBC) 321 # define ZYAN_UNREACHABLE for(;;) 322 #elif defined(ZYAN_WINDOWS) && defined(ZYAN_KERNEL) 323 # define ZYAN_UNREACHABLE { __fastfail(0); for(;;){} } 324 #else 325 # include <stdlib.h> 326 # define ZYAN_UNREACHABLE { assert(0); abort(); } 327 #endif 328 329 /* ============================================================================================== */ 330 /* Utils */ 331 /* ============================================================================================== */ 332 333 /* ---------------------------------------------------------------------------------------------- */ 334 /* General purpose */ 335 /* ---------------------------------------------------------------------------------------------- */ 336 337 /** 338 * Marks the specified parameter as unused. 339 * 340 * @param x The name of the unused parameter. 341 */ 342 #define ZYAN_UNUSED(x) (void)(x) 343 344 /** 345 * Intentional fallthrough. 346 */ 347 #if defined(ZYAN_GCC) && __GNUC__ >= 7 348 # define ZYAN_FALLTHROUGH ; __attribute__((__fallthrough__)) 349 #else 350 # define ZYAN_FALLTHROUGH 351 #endif 352 353 /** 354 * Declares a bitfield. 355 * 356 * @param x The size (in bits) of the bitfield. 357 */ 358 #define ZYAN_BITFIELD(x) : x 359 360 /** 361 * Marks functions that require libc (cannot be used with `ZYAN_NO_LIBC`). 362 */ 363 #define ZYAN_REQUIRES_LIBC 364 365 /** 366 * Decorator for `printf`-style functions. 367 * 368 * @param format_index The 1-based index of the format string parameter. 369 * @param first_to_check The 1-based index of the format arguments parameter. 370 */ 371 #if defined(__RESHARPER__) 372 # define ZYAN_PRINTF_ATTR(format_index, first_to_check) \ 373 [[gnu::format(printf, format_index, first_to_check)]] 374 #elif defined(ZYAN_GCC) 375 # define ZYAN_PRINTF_ATTR(format_index, first_to_check) \ 376 __attribute__((format(printf, format_index, first_to_check))) 377 #else 378 # define ZYAN_PRINTF_ATTR(format_index, first_to_check) 379 #endif 380 381 /** 382 * Decorator for `wprintf`-style functions. 383 * 384 * @param format_index The 1-based index of the format string parameter. 385 * @param first_to_check The 1-based index of the format arguments parameter. 386 */ 387 #if defined(__RESHARPER__) 388 # define ZYAN_WPRINTF_ATTR(format_index, first_to_check) \ 389 [[rscpp::format(wprintf, format_index, first_to_check)]] 390 #else 391 # define ZYAN_WPRINTF_ATTR(format_index, first_to_check) 392 #endif 393 394 /* ---------------------------------------------------------------------------------------------- */ 395 /* Arrays */ 396 /* ---------------------------------------------------------------------------------------------- */ 397 398 /** 399 * Returns the length (number of elements) of an array. 400 * 401 * @param a The name of the array. 402 * 403 * @return The number of elements of the given array. 404 */ 405 #define ZYAN_ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) 406 407 /* ---------------------------------------------------------------------------------------------- */ 408 /* Arithmetic */ 409 /* ---------------------------------------------------------------------------------------------- */ 410 411 /** 412 * Returns the smaller value of `a` or `b`. 413 * 414 * @param a The first value. 415 * @param b The second value. 416 * 417 * @return The smaller value of `a` or `b`. 418 */ 419 #define ZYAN_MIN(a, b) (((a) < (b)) ? (a) : (b)) 420 421 /** 422 * Returns the bigger value of `a` or `b`. 423 * 424 * @param a The first value. 425 * @param b The second value. 426 * 427 * @return The bigger value of `a` or `b`. 428 */ 429 #define ZYAN_MAX(a, b) (((a) > (b)) ? (a) : (b)) 430 431 /** 432 * Returns the absolute value of `a`. 433 * 434 * @param a The value. 435 * 436 * @return The absolute value of `a`. 437 */ 438 #define ZYAN_ABS(a) (((a) < 0) ? -(a) : (a)) 439 440 /** 441 * Checks, if the given value is a power of 2. 442 * 443 * @param x The value. 444 * 445 * @return `ZYAN_TRUE`, if the given value is a power of 2 or `ZYAN_FALSE`, if not. 446 * 447 * Note that this macro always returns `ZYAN_TRUE` for `x == 0`. 448 */ 449 #define ZYAN_IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0) 450 451 /** 452 * Checks, if the given value is properly aligned. 453 * 454 * Note that this macro only works for powers of 2. 455 */ 456 #define ZYAN_IS_ALIGNED_TO(x, align) (((x) & ((align) - 1)) == 0) 457 458 /** 459 * Aligns the value to the nearest given alignment boundary (by rounding it up). 460 * 461 * @param x The value. 462 * @param align The desired alignment. 463 * 464 * @return The aligned value. 465 * 466 * Note that this macro only works for powers of 2. 467 */ 468 #define ZYAN_ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1)) 469 470 /** 471 * Aligns the value to the nearest given alignment boundary (by rounding it down). 472 * 473 * @param x The value. 474 * @param align The desired alignment. 475 * 476 * @return The aligned value. 477 * 478 * Note that this macro only works for powers of 2. 479 */ 480 #define ZYAN_ALIGN_DOWN(x, align) (((x) - 1) & ~((align) - 1)) 481 482 /** 483 * Divide the 64bit integer value by the given divisor. 484 * 485 * @param n Variable containing the dividend that will be updated with the result of the 486 * division. 487 * @param divisor The divisor. 488 */ 489 #if defined(ZYAN_LINUX) && defined(ZYAN_KERNEL) 490 # include <asm/div64.h> /* do_div */ 491 # define ZYAN_DIV64(n, divisor) do_div(n, divisor) 492 #else 493 # define ZYAN_DIV64(n, divisor) (n /= divisor) 494 #endif 495 496 /* ---------------------------------------------------------------------------------------------- */ 497 /* Bit operations */ 498 /* ---------------------------------------------------------------------------------------------- */ 499 500 /* 501 * Checks, if the bit at index `b` is required to present the ordinal value `n`. 502 * 503 * @param n The ordinal value. 504 * @param b The bit index. 505 * 506 * @return `ZYAN_TRUE`, if the bit at index `b` is required to present the ordinal value `n` or 507 * `ZYAN_FALSE`, if not. 508 * 509 * Note that this macro always returns `ZYAN_FALSE` for `n == 0`. 510 */ 511 #define ZYAN_NEEDS_BIT(n, b) (((unsigned long)(n) >> (b)) > 0) 512 513 /* 514 * Returns the number of bits required to represent the ordinal value `n`. 515 * 516 * @param n The ordinal value. 517 * 518 * @return The number of bits required to represent the ordinal value `n`. 519 * 520 * Note that this macro returns `0` for `n == 0`. 521 */ 522 #define ZYAN_BITS_TO_REPRESENT(n) \ 523 ( \ 524 ZYAN_NEEDS_BIT(n, 0) + ZYAN_NEEDS_BIT(n, 1) + \ 525 ZYAN_NEEDS_BIT(n, 2) + ZYAN_NEEDS_BIT(n, 3) + \ 526 ZYAN_NEEDS_BIT(n, 4) + ZYAN_NEEDS_BIT(n, 5) + \ 527 ZYAN_NEEDS_BIT(n, 6) + ZYAN_NEEDS_BIT(n, 7) + \ 528 ZYAN_NEEDS_BIT(n, 8) + ZYAN_NEEDS_BIT(n, 9) + \ 529 ZYAN_NEEDS_BIT(n, 10) + ZYAN_NEEDS_BIT(n, 11) + \ 530 ZYAN_NEEDS_BIT(n, 12) + ZYAN_NEEDS_BIT(n, 13) + \ 531 ZYAN_NEEDS_BIT(n, 14) + ZYAN_NEEDS_BIT(n, 15) + \ 532 ZYAN_NEEDS_BIT(n, 16) + ZYAN_NEEDS_BIT(n, 17) + \ 533 ZYAN_NEEDS_BIT(n, 18) + ZYAN_NEEDS_BIT(n, 19) + \ 534 ZYAN_NEEDS_BIT(n, 20) + ZYAN_NEEDS_BIT(n, 21) + \ 535 ZYAN_NEEDS_BIT(n, 22) + ZYAN_NEEDS_BIT(n, 23) + \ 536 ZYAN_NEEDS_BIT(n, 24) + ZYAN_NEEDS_BIT(n, 25) + \ 537 ZYAN_NEEDS_BIT(n, 26) + ZYAN_NEEDS_BIT(n, 27) + \ 538 ZYAN_NEEDS_BIT(n, 28) + ZYAN_NEEDS_BIT(n, 29) + \ 539 ZYAN_NEEDS_BIT(n, 30) + ZYAN_NEEDS_BIT(n, 31) \ 540 ) 541 542 /* ---------------------------------------------------------------------------------------------- */ 543 544 /* ============================================================================================== */ 545 546 #endif /* ZYCORE_DEFINES_H */ 547