odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

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