// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// //~ rjf: Safe Casts internal U16 safe_cast_u16(U32 x) { AssertAlways(x <= max_U16); U16 result = (U16)x; return result; } internal U32 safe_cast_u32(U64 x) { AssertAlways(x <= max_U32); U32 result = (U32)x; return result; } internal S32 safe_cast_s32(S64 x) { AssertAlways(x <= max_S32); S32 result = (S32)x; return result; } //////////////////////////////// //~ rjf: Large Base Type Functions internal U128 u128_zero(void) { U128 v = {0}; return v; } internal U128 u128_make(U64 v0, U64 v1) { U128 v = {v0, v1}; return v; } internal B32 u128_match(U128 a, U128 b) { return MemoryMatchStruct(&a, &b); } //////////////////////////////// //~ rjf: Bit Patterns internal U32 u32_from_u64_saturate(U64 x){ U32 x32 = (x > max_U32)?max_U32:(U32)x; return(x32); } internal U64 u64_up_to_pow2(U64 x){ if (x == 0){ x = 1; } else{ x -= 1; x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16); x |= (x >> 32); x += 1; } return(x); } internal S32 extend_sign32(U32 x, U32 size){ U32 high_bit = size * 8; U32 shift = 32 - high_bit; S32 result = ((S32)x << shift) >> shift; return result; } internal S64 extend_sign64(U64 x, U64 size){ U64 high_bit = size * 8; U64 shift = 64 - high_bit; S64 result = ((S64)x << shift) >> shift; return result; } internal F32 inf32(void){ union { U32 u; F32 f; } x; x.u = exponent32; return(x.f); } internal F32 neg_inf32(void){ union { U32 u; F32 f; } x; x.u = sign32 | exponent32; return(x.f); } internal U16 bswap_u16(U16 x) { U16 result = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)); return result; } internal U32 bswap_u32(U32 x) { U32 result = (((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24)); return result; } internal U64 bswap_u64(U64 x) { // TODO(nick): naive bswap, replace with something that is faster like an intrinsic U64 result = (((x & 0xFF00000000000000ULL) >> 56) | ((x & 0x00FF000000000000ULL) >> 40) | ((x & 0x0000FF0000000000ULL) >> 24) | ((x & 0x000000FF00000000ULL) >> 8) | ((x & 0x00000000FF000000ULL) << 8) | ((x & 0x0000000000FF0000ULL) << 24) | ((x & 0x000000000000FF00ULL) << 40) | ((x & 0x00000000000000FFULL) << 56)); return result; } #if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS) internal U64 count_bits_set32(U32 val) { return __popcnt(val); } internal U64 count_bits_set64(U64 val) { return __popcnt64(val); } internal U64 ctz32(U32 mask) { unsigned long idx; _BitScanForward(&idx, mask); return idx; } internal U64 ctz64(U64 mask) { unsigned long idx; _BitScanForward64(&idx, mask); return idx; } internal U64 clz32(U32 mask) { unsigned long idx; _BitScanReverse(&idx, mask); return 31 - idx; } internal U64 clz64(U64 mask) { unsigned long idx; _BitScanReverse64(&idx, mask); return 63 - idx; } #elif COMPILER_CLANG || COMPILER_GCC internal U64 count_bits_set32(U32 val) { return __builtin_popcount(val); } internal U64 count_bits_set64(U64 val) { return __builtin_popcountll(val); } internal U64 ctz32(U32 val) { return __builtin_ctz(val); } internal U64 clz32(U32 val) { return __builtin_clz(val); } internal U64 ctz64(U64 val) { return __builtin_ctzll(val); } internal U64 clz64(U64 val) { return __builtin_clzll(val); } #else # error "Bit intrinsic functions not defined for this compiler." #endif //////////////////////////////// //~ rjf: Enum -> Sign internal S32 sign_from_side_S32(Side side){ return((side == Side_Min)?-1:1); } internal F32 sign_from_side_F32(Side side){ return((side == Side_Min)?-1.f:1.f); } //////////////////////////////// //~ rjf: Memory Functions internal B32 memory_is_zero(void *ptr, U64 size) { B32 result = 1; // break down size U64 extra = (size&0x7); U64 count8 = (size >> 3); // check with 8-byte stride U64 *p64 = (U64*)ptr; if(result) { for(U64 i = 0; i < count8; i += 1, p64 += 1) { if(*p64 != 0) { result = 0; goto done; } } } // check extra if(result) { U8 *p8 = (U8*)p64; for(U64 i = 0; i < extra; i += 1, p8 += 1) { if(*p8 != 0) { result = 0; goto done; } } } done:; return result; } //////////////////////////////// //~ rjf: Text 2D Coordinate/Range Functions internal TxtPt txt_pt(S64 line, S64 column) { TxtPt p = {0}; p.line = line; p.column = column; return p; } internal B32 txt_pt_match(TxtPt a, TxtPt b) { return a.line == b.line && a.column == b.column; } internal B32 txt_pt_less_than(TxtPt a, TxtPt b) { B32 result = 0; if(a.line < b.line) { result = 1; } else if(a.line == b.line) { result = a.column < b.column; } return result; } internal TxtPt txt_pt_min(TxtPt a, TxtPt b) { TxtPt result = b; if(txt_pt_less_than(a, b)) { result = a; } return result; } internal TxtPt txt_pt_max(TxtPt a, TxtPt b) { TxtPt result = a; if(txt_pt_less_than(a, b)) { result = b; } return result; } internal TxtRng txt_rng(TxtPt min, TxtPt max) { TxtRng range = {0}; if(txt_pt_less_than(min, max)) { range.min = min; range.max = max; } else { range.min = max; range.max = min; } return range; } internal TxtRng txt_rng_intersect(TxtRng a, TxtRng b) { TxtRng result = {0}; result.min = txt_pt_max(a.min, b.min); result.max = txt_pt_min(a.max, b.max); if(txt_pt_less_than(result.max, result.min)) { MemoryZeroStruct(&result); } return result; } internal TxtRng txt_rng_union(TxtRng a, TxtRng b) { TxtRng result = {0}; result.min = txt_pt_min(a.min, b.min); result.max = txt_pt_max(a.max, b.max); return result; } internal B32 txt_rng_contains(TxtRng r, TxtPt pt) { B32 result = ((txt_pt_less_than(r.min, pt) || txt_pt_match(r.min, pt)) && txt_pt_less_than(pt, r.max)); return result; } //////////////////////////////// //~ rjf: Toolchain/Environment Enum Functions internal U64 bit_size_from_arch(Arch arch) { // TODO(rjf): metacode U64 arch_bitsize = 0; switch(arch) { case Arch_x64: arch_bitsize = 64; break; case Arch_x86: arch_bitsize = 32; break; case Arch_arm64: arch_bitsize = 64; break; case Arch_arm32: arch_bitsize = 32; break; default: break; } return arch_bitsize; } internal U64 max_instruction_size_from_arch(Arch arch) { // TODO(rjf): make this real return 64; } //////////////////////////////// //~ rjf: Time Functions internal DenseTime dense_time_from_date_time(DateTime date_time){ DenseTime result = 0; result += date_time.year; result *= 12; result += date_time.mon; result *= 31; result += date_time.day; result *= 24; result += date_time.hour; result *= 60; result += date_time.min; result *= 61; result += date_time.sec; result *= 1000; result += date_time.msec; return(result); } internal DateTime date_time_from_dense_time(DenseTime time){ DateTime result = {0}; result.msec = time%1000; time /= 1000; result.sec = time%61; time /= 61; result.min = time%60; time /= 60; result.hour = time%24; time /= 24; result.day = time%31; time /= 31; result.mon = time%12; time /= 12; Assert(time <= max_U32); result.year = (U32)time; return(result); } internal DateTime date_time_from_micro_seconds(U64 time){ DateTime result = {0}; result.micro_sec = time%1000; time /= 1000; result.msec = time%1000; time /= 1000; result.sec = time%60; time /= 60; result.min = time%60; time /= 60; result.hour = time%24; time /= 24; result.day = time%31; time /= 31; result.mon = time%12; time /= 12; Assert(time <= max_U32); result.year = (U32)time; return(result); } internal DateTime date_time_from_unix_time(U64 unix_time) { DateTime date = {0}; date.year = 1970; date.day = 1 + (unix_time / 86400); date.sec = (U32)unix_time % 60; date.min = (U32)(unix_time / 60) % 60; date.hour = (U32)(unix_time / 3600) % 24; for(;;) { for(date.month = 0; date.month < 12; ++date.month) { U64 c = 0; switch(date.month) { case Month_Jan: c = 31; break; case Month_Feb: { if((date.year % 4 == 0) && ((date.year % 100) != 0 || (date.year % 400) == 0)) { c = 29; } else { c = 28; } } break; case Month_Mar: c = 31; break; case Month_Apr: c = 30; break; case Month_May: c = 31; break; case Month_Jun: c = 30; break; case Month_Jul: c = 31; break; case Month_Aug: c = 31; break; case Month_Sep: c = 30; break; case Month_Oct: c = 31; break; case Month_Nov: c = 30; break; case Month_Dec: c = 31; break; default: InvalidPath; } if(date.day <= c) { goto exit; } date.day -= c; } ++date.year; } exit:; return date; } //////////////////////////////// //~ rjf: Non-Fancy Ring Buffer Reads/Writes internal U64 ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size) { Assert(src_data_size <= ring_size); { U64 ring_off = ring_pos%ring_size; U64 bytes_before_split = ring_size-ring_off; U64 pre_split_bytes = Min(bytes_before_split, src_data_size); U64 pst_split_bytes = src_data_size-pre_split_bytes; void *pre_split_data = src_data; void *pst_split_data = ((U8 *)src_data + pre_split_bytes); MemoryCopy(ring_base+ring_off, pre_split_data, pre_split_bytes); MemoryCopy(ring_base+0, pst_split_data, pst_split_bytes); } return src_data_size; } internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size) { Assert(read_size <= ring_size); { U64 ring_off = ring_pos%ring_size; U64 bytes_before_split = ring_size-ring_off; U64 pre_split_bytes = Min(bytes_before_split, read_size); U64 pst_split_bytes = read_size-pre_split_bytes; MemoryCopy(dst_data, ring_base+ring_off, pre_split_bytes); MemoryCopy((U8 *)dst_data + pre_split_bytes, ring_base+0, pst_split_bytes); } return read_size; } //////////////////////////////// internal U64 u64_array_bsearch(U64 *arr, U64 count, U64 value) { if(count > 1 && arr[0] <= value && value < arr[count-1]) { U64 l = 0; U64 r = count - 1; for(; l <= r; ) { U64 m = l + (r - l) / 2; if(arr[m] == value) { return m; } else if(arr[m] < value) { l = m + 1; } else { r = m - 1; } } } else if (count == 1 && arr[0] == value) { return 0; } return max_U64; } //////////////////////////////// internal U64 index_of_zero_u32(U32 *ptr, U64 count) { for (U64 i = 0; i < count; i += 1) { if (ptr[i] == 0) { return i; } } return max_U64; } internal U64 index_of_zero_u64(U64 *ptr, U64 count) { for (U64 i = 0; i < count; i += 1) { if (ptr[i] == 0) { return i; } } return max_U64; } //////////////////////////////// //~ rjf: Third Party Includes #if !BUILD_SUPPLEMENTARY_UNIT #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wsign-conversion" #elif defined(_MSC_VER) #pragma warning (push, 0) #endif # define STB_SPRINTF_IMPLEMENTATION # define STB_SPRINTF_STATIC # include "third_party/stb/stb_sprintf.h" #endif #if defined(__clang__) #pragma clang diagnostic pop #elif defined(_MSC_VER) #pragma warning (pop, 0) #endif //////////////////////////////// //~ rjf: String <-> Integer Tables read_only global U8 integer_symbols[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', }; // NOTE(rjf): Includes reverses for uppercase and lowercase hex. read_only global U8 integer_symbol_reverse[128] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, }; read_only global U8 base64[64] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '$', }; read_only global U8 base64_reverse[128] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, 0xFF,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32, 0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0x3E, 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF, };