#pragma once #include #include #include #include #include #ifdef __has_feature #if __has_feature(address_sanitizer) #define USE_ASAN 1 #endif #endif #if defined(__SANITIZE_ADDRESS__) #define USE_ASAN 1 #endif // Types typedef int8_t S8; typedef int16_t S16; typedef int32_t S32; typedef int64_t S64; typedef uint8_t U8; typedef uint16_t U16; typedef uint32_t U32; typedef uint64_t U64; typedef float F32; typedef double F64; #if defined(__FLT128_MANT_DIG__) typedef _Float128 F128; #elif defined(__SIZEOF_FLOAT128__) typedef __float128 F128; #endif #ifdef __SIZEOF_INT128__ typedef __int128 S128; typedef unsigned __int128 U128; #endif #define U8_Max ((U8) 0xff) #define U16_Max ((U16)0xffff) #define U32_Max ((U32)0xffffffff) #define U64_Max ((U64)0xffffffffffffffffULL) #define U8_Min ((U8) 0x80) #define U16_Min ((U16)0x8000) #define U32_Min ((U32)0x80000000) #define U64_Min ((U64)0x8000000000000000ULL) #define S8_Max ((S8) 0x7f) #define S16_Max ((S16)0x7fff) #define S32_Max ((S32)0x7fffffff) #define S64_Max ((S64)0x7fffffffffffffffLL) #define S8_Min ((S8) 0x80) #define S16_Min ((S16)0x8000) #define S32_Min ((S32)0x80000000) #define S64_Min ((S64)0x8000000000000000LL) // asserts #define Trap() __builtin_trap() #define Abort() __builtin_abort() #define Assert(x) do { if (!(x)) { Trap(); }} while(0) #define NotImplemented Assert(!"Not Implemented") #define ShouldNotHappen Assert(!"This should not happen") #define StaticAssert(expr) typedef int STATIC_ASSERT_FAILED[(expr) ? 1 : -1] // misc utilities #define Max(a, b) \ ({ \ __typeof__(a) _amx = (a); \ __typeof__(b) _bmx = (b); \ _amx > _bmx ? _amx : _bmx;\ }) #define Min(a, b) \ ({ \ __typeof__(a) _amn = (a); \ __typeof__(b) _bmn = (b); \ _amn < _bmn ? _amn : _bmn; \ }) #define ArraySize(a) (sizeof(a) / sizeof((a)[0])) #define Swap(a, b) \ do { \ __typeof__(a) tmp_ = (a); \ (a) = (b); \ (b) = tmp_; \ } while (0) #define ContainerOf(ptr, type, member) \ ({ \ typeof(((type *)0)->member) *__mptr = (ptr); \ (type *)((void *)(unsigned char *)__mptr - offsetof(type, member)); \ }) #define ConstContainerOf(ptr, type, member) \ ({ \ const typeof(((const type *)0)->member) *__mptr = (ptr); \ (const type *)((const void *)(const unsigned char *)__mptr - offsetof(const type, member)); \ }) #define AlignUpPow2(val, align) (((val) + (align) - 1UL) & ~((align) - 1UL)) #define AlignDownPow2(val, align) ((val) & ~((align) - 1UL)) #define IsPow2(x) ((x) && !((x) & ((x) - 1UL))) #define IsPow2OrZero(x) (!((x) & ((x) - 1UL))) #define IsAlignedTo(x, y) (IsPow2(y) && !((x) & ((y) - 1UL))) #define GetBit(val, idx) (((val) >> (idx)) & 1) // Get n_bits starting at idx going left #define GetBits(val, n_bits, idx) \ (((n_bits) == 0 ? 0 : ((value) >> (idx)) & ((((__typeof__(val))(1) << (n_bits)) - 1))) #define STRINGIFY(x) STRINGIFY_HLP(x) #define STRINGIFY_HLP(x) #x #define SRC_LOCATION __FILE__ ":" STRINGIFY(__LINE__) #ifdef DEBUG #define TRACEF(fmt, ...) \ do { \ fprintf(stdout, "%s (%s)\t" fmt, SRC_LOCATION, __FUNCTION__, \ ##__VA_ARGS__); \ fflush(stdout); \ } while (0) #else #define TRACEF(fmt, ...) \ do { \ } while (0) #endif /** * Ceiling of X / y , or round up x / y * (e.g 100/9 == 12, 3/2 == 2) * x + y must not overflow. * * @param x numerator, must be positive * @param y denominator * @return x/y rounded up */ #define CeilDiv(x, y) (((x) + ((y) - 1)) / (y)) /** * Round x up to nearest multiple of y * e.g. RoundUp(30,48) == 48 * e.g. RoundUp(49,48) == 96 * * @param x numerator, must be positive * @param y denominator * @return x rounded up to nearest multiple of y */ #define RoundUpToMultiple(x, y) (CeilDiv((x), (y)) * (y)) /** * Round x down to nearest multiple of y * e.g. RoundDown(30,48) == 0 * e.g. RoundDown(49,48) == 48 * * @param x numerator, must be positive * @param y denominator * @return x rounded down nearest multiple of y */ #define RounDownToMultiple(x, y) ((x) / (y) * (y)) #define Clamp(val, min, max) (((val) < (min)) ? (min) : ((val) > (max)) ? (max) : (val)) #ifdef __GNUC__ #define INLINE inline __attribute__((always_inline, flatten)) #else #define INLINE inline #endif #ifdef __cplusplus #define C_LINKAGE_BEGIN extern "C" { #define C_LINKAGE_END } #define C_LINKAGE extern "C" #else #define C_LINKAGE_BEGIN #define C_LINKAGE_END #define C_LINKAGE #endif /** Indicate the variable is unused. */ #define UNUSED(x) x __attribute__((unused)) // sizes #define Bytes(n) ((U64)(n)) #define KB(n) (((U64)(n)) << 10) #define MB(n) (((U64)(n)) << 20) #define GB(n) (((U64)(n)) << 30) #define TB(n) (((U64)(n)) << 40) #define Thousand(n) (((U64)(n) * 1000)) #define Million(n) (((U64)(n) * 1000000)) #define Billion(n) (((U64)(n) * 1000000000)) // memory #define MemSet(ptr, val, len) memset(ptr, val, len) #ifdef USE_ASAN #define MemoryZero(ptr, len) memset(ptr, 0, len) // explicity bzero is usually not being intercepted #else #define MemoryZero(ptr, len) explicit_bzero(ptr, len) #endif #define MemMove(dst, src, len) memmove(dst, src, len) #define MemCopy(dst, src, len) memcpy(dst, src, len) #define MemAppend(dst, src, len) mempcpy(dst, src, len) // atomics #define Atomic(type) _Atomic(type) #define AtomicSub(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) #define AtomicAdd(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) #define AtomicDec(ptr) AtomicSub((ptr), 1) #define AtomicInc(ptr) AtomicAdd((ptr), 1) #define AtomicGet(ptr) __c11_atomic_load((ptr), __ATOMIC_SEQ_CST) #define AtomicCAS(ptr, oldval, newval) \ __atomic_compare_exchange((ptr), (oldval), (newval),0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) #define MemoryBarrier() __atomic_thread_fence(UC_ORDER_CST) #define CompilerBarrier() __asm__ __volatile__("": : :"memory") // Saturating operations #define SaturatingAdd(a, b, type, max_val)\ ({type res ;\ if (__builtin_add_overflow(a, b, &res)) {\ res = max_val;}\ res;}) #define SaturatingSub(a, b, type)\ ({type res ;\ if (__builtin_sub_overflow(a, b, &res)) {\ res = 0;}\ res;}) #define SaturatingMult(a, b, type, max_val)\ ({type res ;\ if (__builtin_mul_overflow(a, b, &res)) {\ res = max_val;}\ res;}) static INLINE U8 SaturatingAddU8(U8 a, U8 b) { return SaturatingAdd(a, b, U8, U8_Max); } static INLINE U8 SaturatingSubU8(U8 a, U8 b) { return SaturatingSub(a, b, U8); } static INLINE U8 SaturatingMult8(U8 a, U8 b) { return SaturatingMult(a, b, U8, U8_Max); } static INLINE U16 SaturatingAdd16(U16 a, U16 b) { return SaturatingAdd(a, b, U16, U16_Max); } static INLINE U16 SaturatingSubU16(U16 a, U16 b) { return SaturatingSub(a, b, U16); } static INLINE U16 SaturatingMultU16(U16 a, U16 b) { return SaturatingMult(a, b, U16, U16_Max); } static INLINE U32 SaturatingAdd32(U32 a, U32 b) { return SaturatingAdd(a, b, U32, U32_Max); } static INLINE U32 SaturatingSub32(U32 a, U32 b) { return SaturatingSub(a, b, U32); } static INLINE U32 SaturatingMult32(U32 a, U32 b) { return SaturatingMult(a, b, U32, U32_Max); } static INLINE U64 SaturatingAdd64(U64 a, U64 b) { return SaturatingAdd(a, b, U64, U64_Max); } static INLINE U64 SaturatingSubU64(U64 a, U64 b) { return SaturatingSub(a, b, U64); } static INLINE U64 SaturatingMult64(U64 a, U64 b) { return SaturatingMult(a, b, U64, U64_Max); } // address-sanitizer helpers (-fsanitize=address) #ifdef USE_ASAN #include #define ASAN_POISON_MEMORY_REGION(addr, size) \ __asan_poison_memory_region((addr), (size)) #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ __asan_unpoison_memory_region((addr), (size)) #else #define ASAN_POISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) #endif