api-internal_p.h (26007B)
1 // This file is part of Blend2D project <https://blend2d.com> 2 // 3 // See blend2d.h or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 #ifndef BLEND2D_API_INTERNAL_P_H_INCLUDED 7 #define BLEND2D_API_INTERNAL_P_H_INCLUDED 8 9 #include "api.h" 10 #include "api-impl.h" 11 #include "object.h" 12 13 // C Headers 14 // ========= 15 16 // NOTE: Some headers are already included by <api.h>. This should be useful for creating an overview of what 17 // Blend2D really needs globally to be included. 18 #include <math.h> 19 #include <stdarg.h> 20 #include <stddef.h> 21 #include <stdint.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 // C++ Headers 26 // =========== 27 28 // We are just fine with <math.h>, however, there are some useful overloads in C++'s <cmath> that are nicer to use 29 // than those in <math.h>. Mostly low-level functionality like Math::is_finite() relies on <cmath> instead of <math.h>. 30 #include <cmath> 31 #include <limits> 32 #include <type_traits> 33 34 // Platform Specific Headers 35 // ========================= 36 37 #if defined(_WIN32) 38 //! \cond NEVER 39 #if !defined(WIN32_LEAN_AND_MEAN) 40 #define WIN32_LEAN_AND_MEAN 41 #endif 42 #if !defined(NOMINMAX) 43 #define NOMINMAX 44 #endif 45 //! \endcond 46 47 #include <windows.h> // Required to build Blend2D on Windows platform. 48 #include <synchapi.h> // Synchronization primitivess. 49 #endif 50 51 // Some intrinsics defined by MSVC compiler are useful and used across the library. 52 #ifdef _MSC_VER 53 #include <intrin.h> 54 #endif 55 56 //! \cond INTERNAL 57 //! \addtogroup bl_globals 58 //! \{ 59 60 // Build - Target Architecture & Optimizations 61 // =========================================== 62 63 //! \cond INTERNAL 64 //! \addtogroup blend2d_internal 65 //! \{ 66 67 #if defined(__wasm64__) 68 #define BL_TARGET_ARCH_WASM 64 69 #elif defined(__wasm32__) || defined(__wasm__) 70 #define BL_TARGET_ARCH_WASM 32 71 #else 72 #define BL_TARGET_ARCH_WASM 0 73 #endif 74 75 #if defined(_M_X64) || defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) 76 #define BL_TARGET_ARCH_X86 64 77 #elif defined(_M_IX86) || defined(__i386) || defined(__i386__) 78 #define BL_TARGET_ARCH_X86 32 79 #else 80 #define BL_TARGET_ARCH_X86 0 81 #endif 82 83 #if defined(_M_ARM64) || defined(__ARM64__) || defined(__aarch64__) 84 #define BL_TARGET_ARCH_ARM 64 85 #elif defined(_M_ARM) || defined(_M_ARMT) || defined(__arm__) || defined(__thumb__) || defined(__thumb2__) 86 #define BL_TARGET_ARCH_ARM 32 87 #else 88 #define BL_TARGET_ARCH_ARM 0 89 #endif 90 91 #if defined(_MIPS_ARCH_MIPS64) || defined(__mips64) 92 #define BL_TARGET_ARCH_MIPS 64 93 #elif defined(_MIPS_ARCH_MIPS32) || defined(_M_MRX000) || defined(__mips) || defined(__mips__) 94 #define BL_TARGET_ARCH_MIPS 32 95 #else 96 #define BL_TARGET_ARCH_MIPS 0 97 #endif 98 99 #define BL_TARGET_ARCH_BITS (BL_TARGET_ARCH_X86 | BL_TARGET_ARCH_ARM | BL_TARGET_ARCH_MIPS | BL_TARGET_ARCH_WASM) 100 #if BL_TARGET_ARCH_BITS == 0 101 #undef BL_TARGET_ARCH_BITS 102 #if defined(__LP64__) || defined(_LP64) 103 #define BL_TARGET_ARCH_BITS 64 104 #else 105 #define BL_TARGET_ARCH_BITS 32 106 #endif 107 #endif 108 109 // Defined when it's safe to assume that std::atomic<uint64_t> would be non locking. We can always assume this on 110 // X86 architecture even 32-bit as it provides CMPXCHG8B, but we don't assume this on other architectures like ARM. 111 #if BL_TARGET_ARCH_BITS >= 64 || BL_TARGET_ARCH_X86 != 0 112 #define BL_TARGET_HAS_ATOMIC_64B 1 113 #else 114 #define BL_TARGET_HAS_ATOMIC_64B 0 115 #endif 116 117 #if !defined(BL_BUILD_NO_JIT) 118 #if BL_TARGET_ARCH_X86 != 0 119 #define BL_JIT_ARCH_X86 120 #elif BL_TARGET_ARCH_ARM == 64 121 #define BL_JIT_ARCH_A64 122 #endif 123 #endif // !BL_BUILD_NO_JIT 124 125 // Build optimizations control compile-time optimizations to be used by Blend2D and C++ compiler. These optimizations 126 // are not related to the code-generator optimizations (JIT) that are always auto-detected at runtime. 127 #if BL_TARGET_ARCH_X86 128 #if defined(BL_BUILD_OPT_AVX512) && !defined(BL_BUILD_OPT_AVX2) 129 #define BL_BUILD_OPT_AVX2 130 #endif 131 #if defined(BL_BUILD_OPT_AVX2) && !defined(BL_BUILD_OPT_AVX) 132 #define BL_BUILD_OPT_AVX 133 #endif 134 #if defined(BL_BUILD_OPT_AVX) && !defined(BL_BUILD_OPT_SSE4_2) 135 #define BL_BUILD_OPT_SSE4_2 136 #endif 137 #if defined(BL_BUILD_OPT_SSE4_2) && !defined(BL_BUILD_OPT_SSE4_1) 138 #define BL_BUILD_OPT_SSE4_1 139 #endif 140 #if defined(BL_BUILD_OPT_SSE4_1) && !defined(BL_BUILD_OPT_SSSE3) 141 #define BL_BUILD_OPT_SSSE3 142 #endif 143 #if defined(BL_BUILD_OPT_SSSE3) && !defined(BL_BUILD_OPT_SSE3) 144 #define BL_BUILD_OPT_SSE3 145 #endif 146 #if defined(BL_BUILD_OPT_SSE3) && !defined(BL_BUILD_OPT_SSE2) 147 #define BL_BUILD_OPT_SSE2 148 #endif 149 150 #if defined(__AVX512F__) && defined(__AVX512BW__) && defined(__AVX512DQ__) && defined(__AVX512CD__) && defined(__AVX512VL__) 151 #define BL_TARGET_OPT_AVX512 152 #endif 153 #if defined(BL_TARGET_OPT_AVX512) || defined(__AVX2__) 154 #define BL_TARGET_OPT_AVX2 155 #endif 156 #if defined(BL_TARGET_OPT_AVX2) || defined(__AVX__) 157 #define BL_TARGET_OPT_AVX 158 #endif 159 #if defined(BL_TARGET_OPT_AVX) || defined(__SSE4_2__) 160 #define BL_TARGET_OPT_SSE4_2 161 #endif 162 #if defined(BL_TARGET_OPT_SSE4_2) || defined(__SSE4_1__) 163 #define BL_TARGET_OPT_SSE4_1 164 #endif 165 #if defined(BL_TARGET_OPT_SSE4_1) || defined(__SSSE3__) 166 #define BL_TARGET_OPT_SSSE3 167 #endif 168 #if defined(BL_TARGET_OPT_SSSE3) || defined(__SSE3__) 169 #define BL_TARGET_OPT_SSE3 170 #endif 171 #if defined(BL_TARGET_OPT_SSE3) || (BL_TARGET_ARCH_X86 == 64 || defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)) 172 #define BL_TARGET_OPT_SSE2 173 #endif 174 #if defined(BL_TARGET_OPT_SSE2) || (BL_TARGET_ARCH_X86 == 64 || defined(__SSE__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) 175 #define BL_TARGET_OPT_SSE 176 #endif 177 178 #if !defined(BL_TARGET_OPT_BMI2) && defined(__BMI2__) 179 #define BL_TARGET_OPT_BMI2 180 #endif 181 182 #if !defined(BL_TARGET_OPT_POPCNT) && (defined(__POPCNT__) || defined(BL_TARGET_OPT_SSE4_2)) 183 #define BL_TARGET_OPT_POPCNT 184 #endif 185 #endif 186 187 #if BL_TARGET_ARCH_ARM && (BL_TARGET_ARCH_ARM == 64 || defined(__ARM_NEON__)) 188 #ifndef BL_TARGET_OPT_ASIMD 189 #define BL_TARGET_OPT_ASIMD 190 #endif // BL_TARGET_OPT_ASIMD 191 #ifndef BL_BUILD_OPT_ASIMD 192 #define BL_BUILD_OPT_ASIMD 193 #endif // BL_BUILD_OPT_ASIMD 194 #endif 195 196 //! \} 197 //! \endcond 198 199 // C++ Compiler Support 200 // ==================== 201 202 // Some compilers won't optimize our stuff if we won't tell them. However, we have to be careful as Blend2D doesn't 203 // use fast-math by default. So when applicable we turn some optimizations on and off locally, but not globally. 204 // 205 // This has also a lot of downsides. For example all wrappers in "std" namespace are compiled with default flags so 206 // even when we force the compiler to follow certain behavior it would only work if we use the "original" functions 207 // and not those wrapped in `std` namespace (so use floor and not std::floor, etc). 208 #if defined(_MSC_VER) && !defined(__clang__) 209 #define BL_PRAGMA_FAST_MATH_PUSH __pragma(float_control(precise, off, push)) 210 #define BL_PRAGMA_FAST_MATH_POP __pragma(float_control(pop)) 211 #else 212 #define BL_PRAGMA_FAST_MATH_PUSH 213 #define BL_PRAGMA_FAST_MATH_POP 214 #endif 215 216 #if defined(__clang__) || defined(__has_attribute__) 217 #define BL_CC_HAS_ATTRIBUTE(x) __has_attribute(x) 218 #else 219 #define BL_CC_HAS_ATTRIBUTE(x) 0 220 #endif 221 222 //! \def BL_HIDDEN 223 //! 224 //! Decorates a function that is used across more than one source file, but should never be exported. Expands to 225 //! a compiler-specific code that affects the visibility. 226 #if defined(__GNUC__) && !defined(__MINGW32__) 227 #define BL_HIDDEN __attribute__((__visibility__("hidden"))) 228 #else 229 #define BL_HIDDEN 230 #endif 231 232 //! \def BL_OPTIMIZE 233 //! 234 //! Decorates a function that should be highly optimized by C++ compiler. In general Blend2D uses "-O2" optimization 235 //! level on GCC and Clang, this macro would change the optimization level to "-O3" for the decorated function. 236 #if !defined(BL_BUILD_DEBUG) && (BL_CC_HAS_ATTRIBUTE(__optimize__) || (!defined(__clang__) && defined(__GNUC__))) 237 #define BL_OPTIMIZE __attribute__((__optimize__("O3"))) 238 #else 239 #define BL_OPTIMIZE 240 #endif 241 242 //! \def BL_NOINLINE 243 //! 244 //! Decorates a function that should never be inlined. Sometimes used by Blend2D to decorate functions that are 245 //! either called rarely or that are called from other code in corner cases - like buffer reallocation, etc... 246 #if defined(__GNUC__) 247 #define BL_NOINLINE __attribute__((__noinline__)) 248 #elif defined(_MSC_VER) 249 #define BL_NOINLINE __declspec(noinline) 250 #else 251 #define BL_NOINLINE 252 #endif 253 254 //! \def BL_FLATTEN 255 //! 256 //! Either `__attribute__((flatten))` or nothing, if not supported. 257 #if defined(__GNUC__) 258 #define BL_FLATTEN __attribute__((__flatten__)) 259 #else 260 #define BL_FLATTEN 261 #endif 262 263 //! \def BL_STDCALL 264 //! 265 //! Calling convention used by Windows. 266 #if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__) 267 #define BL_STDCALL __attribute__((__stdcall__)) 268 #elif defined(_MSC_VER) 269 #define BL_STDCALL __stdcall 270 #else 271 #define BL_STDCALL 272 #endif 273 274 //! \def BL_OPTIMIZED_CALL 275 //! 276 //! Optimized calling convention used internally in some places. 277 #define BL_OPTIMIZED_CALL 278 279 //! \def BL_UNALIGNED_TYPE(TYPE, ALIGNMENT) 280 //! 281 //! Defines a type, that is aligned to less than its native alignment. In general this is not supported by the 282 //! C++ alignas() keyword, which only allows to increase the alignment. Compilers that support unaligned types 283 //! can generate nicer code when such type is accessed and UBSAN would not complain about such accesses, if 284 //! properly annotated. 285 #if defined(__GNUC__) 286 #define BL_UNALIGNED_TYPE(TYPE, ALIGNMENT) __attribute__((__aligned__(ALIGNMENT))) __attribute__((__may_alias__)) TYPE 287 #elif defined(_MSC_VER) 288 #define BL_UNALIGNED_TYPE(TYPE, ALIGNMENT) __declspec(align(ALIGNMENT)) TYPE 289 #else 290 #define BL_UNALIGNED_TYPE(TYPE, ALIGNMENT) TYPE 291 #endif 292 293 //! \def BL_MAY_ALIAS 294 //! 295 //! Expands to `__attribute__((__may_alias__))` if supported. 296 #if defined(__GNUC__) 297 #define BL_MAY_ALIAS __attribute__((__may_alias__)) 298 #else 299 #define BL_MAY_ALIAS 300 #endif 301 302 //! \def BL_NOUNROLL 303 //! 304 //! Compiler-specific macro that annotates a do/for/while loop to not get unrolled. 305 #if defined(__clang__) 306 #define BL_NOUNROLL _Pragma("nounroll") 307 #elif defined(__GNUC__) && (__GNUC__ >= 8) 308 // NOTE: We could use `_Pragma("GCC unroll 1")`, however, this doesn't apply to all loops and GCC emits a lot of 309 // warnings such as "ignoring loop annotation", which cannot be turned off globally nor locally. So we disable 310 // loop annotations when compiling with GCC. This comment is here so we can re-enable in the future. 311 #define BL_NOUNROLL 312 #else 313 #define BL_NOUNROLL 314 #endif 315 316 //! \def BL_RUNTIME_INITIALIZER 317 //! 318 //! Static initialization in C++ is full of surpsises and basically nothing is guaranteed. When Blend2D is compiled 319 //! as a shared library everything is fine, however, when it's compiled as a static library and user uses statically 320 //! allocated Blend2D objects then the object may initialize even before the library - this tries to solve that issue. 321 #if defined(__clang__) || (defined(__GNUC__) && !defined(__APPLE__)) 322 #define BL_RUNTIME_INITIALIZER __attribute__((init_priority(102))) 323 #else 324 #define BL_RUNTIME_INITIALIZER 325 #endif 326 327 #if defined(BL_BUILD_DEBUG) && !defined(__OPTIMIZE__) 328 #define BL_INLINE_IF_NOT_DEBUG 329 #else 330 #define BL_INLINE_IF_NOT_DEBUG BL_INLINE 331 #endif 332 333 //! \def BL_API_IMPL 334 //! 335 //! Decorator used to mark all functions and variables that are exported - it expands to "extern C", which ensures 336 //! that an exported function or variable can be implemented within a private namespace and it would still be exported 337 //! properly. 338 #define BL_API_IMPL extern "C" BL_API 339 340 #define BL_STRINGIFY_WRAP(N) #N 341 #define BL_STRINGIFY(N) BL_STRINGIFY_WRAP(N) 342 343 #define BL_STATIC_ASSERT(...) static_assert(__VA_ARGS__, "Failed BL_STATIC_ASSERT(" #__VA_ARGS__ ")") 344 345 // Internal C++ Macros 346 // =================== 347 348 //! \def BL_NONCOPYABLE 349 //! 350 //! Makes a class noncopyable by making its copy constructor and copy assignment operator deleted. 351 #define BL_NONCOPYABLE(...) \ 352 __VA_ARGS__(const __VA_ARGS__& other) = delete; \ 353 __VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; 354 355 //! \def BL_NOT_REACHED() 356 //! 357 //! Run-time assertion used in code that should never be reached. 358 #ifdef BL_BUILD_DEBUG 359 #define BL_NOT_REACHED() bl_runtime_assertion_failure(__FILE__, __LINE__, "BL_NOT_REACHED()") 360 #elif defined(__GNUC__) 361 #define BL_NOT_REACHED() __builtin_unreachable() 362 #else 363 #define BL_NOT_REACHED() BL_ASSUME(0) 364 #endif 365 366 #if defined(_MSC_VER) 367 #define BL_RESTRICT __restrict 368 #elif defined(__GNUC__) 369 #define BL_RESTRICT __restrict__ 370 #else 371 #define BL_RESTRICT 372 #endif 373 374 #define BL_ARRAY_SIZE(X) uint32_t(sizeof(X) / sizeof(X[0])) 375 #define BL_OFFSET_OF(STRUCT, MEMBER) ((int)(offsetof(STRUCT, MEMBER))) 376 377 #define BL_PROPAGATE_(exp, cleanup) \ 378 do { \ 379 BLResult _result_to_propagate = (exp); \ 380 if (BL_UNLIKELY(_result_to_propagate != BL_SUCCESS)) { \ 381 cleanup \ 382 return _result_to_propagate; \ 383 } \ 384 } while (0) 385 386 //! Like BL_PROPAGATE, but propagates everything except `BL_RESULT_NOTHING`. 387 #define BL_PROPAGATE_IF_NOT_NOTHING(...) \ 388 do { \ 389 BLResult result_to_propagate = (__VA_ARGS__); \ 390 if (result_to_propagate != BL_RESULT_NOTHING) { \ 391 return result_to_propagate; \ 392 } \ 393 } while (0) 394 395 //! Decorates a base class that has virtual functions. 396 #define BL_OVERRIDE_NEW_DELETE(TYPE) \ 397 BL_INLINE void* operator new(size_t n) noexcept { return malloc(n); } \ 398 BL_INLINE void operator delete(void* p) noexcept { if (p) free(p); } \ 399 \ 400 BL_INLINE void* operator new(size_t, const BLInternal::PlacementNew& p) noexcept { return p.ptr; } \ 401 BL_INLINE void operator delete(void*, void*) noexcept {} 402 403 //! \def BL_DEFINE_ENUM_FLAGS(T) 404 //! 405 //! Defines operations for enumeration flags. 406 #ifdef _DOXYGEN 407 #define BL_DEFINE_ENUM_FLAGS(T) 408 #else 409 #define BL_DEFINE_ENUM_FLAGS(T) \ 410 static BL_INLINE_CONSTEXPR T operator~(T a) noexcept { \ 411 return T(~std::underlying_type_t<T>(a)); \ 412 } \ 413 \ 414 static BL_INLINE_CONSTEXPR T operator|(T a, T b) noexcept { \ 415 return T(std::underlying_type_t<T>(a) | std::underlying_type_t<T>(b)); \ 416 } \ 417 static BL_INLINE_CONSTEXPR T operator&(T a, T b) noexcept { \ 418 return T(std::underlying_type_t<T>(a) & std::underlying_type_t<T>(b)); \ 419 } \ 420 static BL_INLINE_CONSTEXPR T operator^(T a, T b) noexcept { \ 421 return T(std::underlying_type_t<T>(a) ^ std::underlying_type_t<T>(b)); \ 422 } \ 423 \ 424 static BL_INLINE_CONSTEXPR T& operator|=(T& a, T b) noexcept { \ 425 a = T(std::underlying_type_t<T>(a) | std::underlying_type_t<T>(b)); \ 426 return a; \ 427 } \ 428 static BL_INLINE_CONSTEXPR T& operator&=(T& a, T b) noexcept { \ 429 a = T(std::underlying_type_t<T>(a) & std::underlying_type_t<T>(b)); \ 430 return a; \ 431 } \ 432 static BL_INLINE_CONSTEXPR T& operator^=(T& a, T b) noexcept { \ 433 a = T(std::underlying_type_t<T>(a) ^ std::underlying_type_t<T>(b)); \ 434 return a; \ 435 } 436 #endif 437 438 //! \def BL_DEFINE_STRONG_TYPE(C, T) 439 //! 440 //! Defines a strong type `C` that wraps a value of `T`. 441 #define BL_DEFINE_STRONG_TYPE(C, T) \ 442 struct C { \ 443 T _v; \ 444 \ 445 BL_INLINE_NODEBUG C() = default; \ 446 BL_INLINE_CONSTEXPR explicit C(T x) noexcept : _v(x) {} \ 447 BL_INLINE_CONSTEXPR C(const C& other) noexcept = default; \ 448 \ 449 BL_INLINE_CONSTEXPR T value() const noexcept { return _v; } \ 450 \ 451 BL_INLINE_CONSTEXPR T* value_ptr() noexcept { return &_v; } \ 452 BL_INLINE_CONSTEXPR const T* value_ptr() const noexcept { return &_v; } \ 453 \ 454 BL_INLINE_CONSTEXPR C& operator=(T x) noexcept { _v = x; return *this; }; \ 455 BL_INLINE_CONSTEXPR C& operator=(const C& x) noexcept { _v = x._v; return *this; } \ 456 \ 457 BL_INLINE_CONSTEXPR C operator+(T x) const noexcept { return C(_v + x); } \ 458 BL_INLINE_CONSTEXPR C operator-(T x) const noexcept { return C(_v - x); } \ 459 BL_INLINE_CONSTEXPR C operator*(T x) const noexcept { return C(_v * x); } \ 460 BL_INLINE_CONSTEXPR C operator/(T x) const noexcept { return C(_v / x); } \ 461 \ 462 BL_INLINE_CONSTEXPR C operator+(const C& x) const noexcept { return C(_v + x._v); } \ 463 BL_INLINE_CONSTEXPR C operator-(const C& x) const noexcept { return C(_v - x._v); } \ 464 BL_INLINE_CONSTEXPR C operator*(const C& x) const noexcept { return C(_v * x._v); } \ 465 BL_INLINE_CONSTEXPR C operator/(const C& x) const noexcept { return C(_v / x._v); } \ 466 \ 467 BL_INLINE_CONSTEXPR C& operator+=(T x) noexcept { _v += x; return *this; } \ 468 BL_INLINE_CONSTEXPR C& operator-=(T x) noexcept { _v -= x; return *this; } \ 469 BL_INLINE_CONSTEXPR C& operator*=(T x) noexcept { _v *= x; return *this; } \ 470 BL_INLINE_CONSTEXPR C& operator/=(T x) noexcept { _v /= x; return *this; } \ 471 \ 472 BL_INLINE_CONSTEXPR C& operator+=(const C& x) noexcept { _v += x._v; return *this; } \ 473 BL_INLINE_CONSTEXPR C& operator-=(const C& x) noexcept { _v -= x._v; return *this; } \ 474 BL_INLINE_CONSTEXPR C& operator*=(const C& x) noexcept { _v *= x._v; return *this; } \ 475 BL_INLINE_CONSTEXPR C& operator/=(const C& x) noexcept { _v /= x._v; return *this; } \ 476 \ 477 BL_INLINE_CONSTEXPR bool operator==(T x) const noexcept { return _v == x; } \ 478 BL_INLINE_CONSTEXPR bool operator!=(T x) const noexcept { return _v != x; } \ 479 BL_INLINE_CONSTEXPR bool operator> (T x) const noexcept { return _v > x; } \ 480 BL_INLINE_CONSTEXPR bool operator>=(T x) const noexcept { return _v >= x; } \ 481 BL_INLINE_CONSTEXPR bool operator< (T x) const noexcept { return _v < x; } \ 482 BL_INLINE_CONSTEXPR bool operator<=(T x) const noexcept { return _v <= x; } \ 483 \ 484 BL_INLINE_CONSTEXPR bool operator==(const C& x) const noexcept { return _v == x._v; } \ 485 BL_INLINE_CONSTEXPR bool operator!=(const C& x) const noexcept { return _v != x._v; } \ 486 BL_INLINE_CONSTEXPR bool operator> (const C& x) const noexcept { return _v > x._v; } \ 487 BL_INLINE_CONSTEXPR bool operator>=(const C& x) const noexcept { return _v >= x._v; } \ 488 BL_INLINE_CONSTEXPR bool operator< (const C& x) const noexcept { return _v < x._v; } \ 489 BL_INLINE_CONSTEXPR bool operator<=(const C& x) const noexcept { return _v <= x._v; } \ 490 }; 491 492 // Internal Macros 493 // =============== 494 495 #define BL_RETURN_ERROR_IF_NULL(ptr) \ 496 do { \ 497 if (!(ptr)) \ 498 return bl_make_error(BL_ERROR_OUT_OF_MEMORY); \ 499 } while (0) 500 501 #define BL_RETURN_ERROR_IF_NULL_(ptr, ...) \ 502 do { \ 503 if (!(ptr)) { \ 504 __VA_ARGS__ \ 505 return bl_make_error(BL_ERROR_OUT_OF_MEMORY); \ 506 } \ 507 } while (0) 508 509 // Internal Types 510 // ============== 511 512 //! A type used to store a pack of bits (typedef to `uintptr_t`). 513 //! 514 //! BitWord should be equal in size to a machine word. 515 using BLBitWord = uintptr_t; 516 517 // Internal Constants 518 // ================== 519 520 //! To make checks for APPEND operation easier. 521 static constexpr BLModifyOp BL_MODIFY_OP_APPEND_START = BLModifyOp(2); 522 //! Mask that can be used to check whether `BLModifyOp` has a grow hint. 523 static constexpr BLModifyOp BL_MODIFY_OP_GROW_MASK = BLModifyOp(1); 524 525 static BL_INLINE_CONSTEXPR bool bl_modify_op_is_assign(BLModifyOp modify_op) noexcept { return modify_op < BL_MODIFY_OP_APPEND_START; } 526 static BL_INLINE_CONSTEXPR bool bl_modify_op_is_append(BLModifyOp modify_op) noexcept { return modify_op >= BL_MODIFY_OP_APPEND_START; } 527 static BL_INLINE_CONSTEXPR bool bl_modify_op_does_grow(BLModifyOp modify_op) noexcept { return (modify_op & BL_MODIFY_OP_GROW_MASK) != 0; } 528 529 // Target CPU Properties Known at Compile Time 530 // ------------------------------------------- 531 532 //! Size of a CPU cache-line or a minimum size if multiple CPUs are used. 533 //! 534 //! Mostly depends on architecture, we use 64 bytes by default. 535 static constexpr uint32_t BL_CACHE_LINE_SIZE = 64; 536 537 // Blend2D Limits and System Allocator Properties 538 // ---------------------------------------------- 539 540 //! Host memory allocator overhead (estimated). 541 static constexpr uint32_t BL_ALLOC_OVERHEAD = uint32_t(sizeof(void*)) * 4u; 542 //! Host memory allocator alignment (can be lower than reality, but cannot be higher). 543 static constexpr uint32_t BL_ALLOC_ALIGNMENT = 8u; 544 545 //! Limits doubling of a container size after the limit size [in bytes] has reached 8MB. The container will 546 //! use a more conservative approach after the threshold has been reached. 547 static constexpr uint32_t BL_ALLOC_GROW_LIMIT = 1u << 23; 548 549 // Alloc Hints Used by Blend2D Containers 550 // -------------------------------------- 551 552 //! Minimum vertices to amortize the check of a matrix type. 553 static constexpr uint32_t BL_MATRIX_TYPE_MINIMUM_SIZE = 16u; 554 555 //! Maximum number of faces per a single font collection. 556 static constexpr uint32_t BL_FONT_DATA_MAX_FACE_COUNT = 256u; 557 558 //! BLResult value that is used internally to signalize that the function didn't succeed, but also didn't fail. 559 //! This is not an error state. At the moment this is only used by \ref BLPixelConverter when setting up optimized 560 //! conversion functions. 561 //! 562 //! \note This result code can be never propagated to the user code! 563 static constexpr uint32_t BL_RESULT_NOTHING = 0xFFFFFFFFu; 564 565 //! Analysis result that describes whether an unknown input is conforming. 566 enum BLDataAnalysis : uint32_t { 567 //! The input data is conforming (stored exactly as expected). 568 BL_DATA_ANALYSIS_CONFORMING = 0, // Must be 0 569 //! The input data is valid, but non-conforming (must be processed). 570 BL_DATA_ANALYSIS_NON_CONFORMING = 1, // Must be 1 571 //! The input data contains an invalid value. 572 BL_DATA_ANALYSIS_INVALID_VALUE = 2 573 }; 574 575 // Internal C++ Structs 576 // ==================== 577 578 template<typename ValueT> 579 struct BLResultT { 580 BLResult code; 581 ValueT value; 582 }; 583 584 // Internal C++ Functions 585 // ====================== 586 587 //! Used to silence warnings about unused arguments or variables. 588 template<typename... Args> 589 static BL_INLINE_NODEBUG void bl_unused(Args&&...) noexcept {} 590 591 template<typename T> 592 static BL_INLINE_CONSTEXPR bool bl_test_flag(const T& x, const T& y) noexcept { 593 return (std::underlying_type_t<T>(x) & std::underlying_type_t<T>(y)) != std::underlying_type_t<T>(0); 594 } 595 596 // TODO: Remove. 597 template<typename T, typename F> 598 static BL_INLINE_NODEBUG void bl_assign_func(T** dst, F f) noexcept { *(void**)dst = (void*)f; } 599 600 // Miscellaneous Internals 601 // ======================= 602 603 //! Checks whether `data_access_flags` is valid. 604 static BL_INLINE_NODEBUG bool bl_data_access_flags_is_valid(uint32_t data_access_flags) noexcept { 605 return data_access_flags == BL_DATA_ACCESS_READ || 606 data_access_flags == BL_DATA_ACCESS_RW; 607 } 608 609 static BL_INLINE_NODEBUG void bl_prefetch_w(const void* p) { (void)p; } 610 611 // BLInternal API Accessible Via 'bl' Namespace 612 // ============================================ 613 614 namespace bl { using namespace BLInternal; } 615 616 //! \} 617 //! \endcond 618 619 #endif // BLEND2D_API_INTERNAL_P_H_INCLUDED