// 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; } internal OperatingSystem operating_system_from_context(void){ OperatingSystem os = OperatingSystem_Null; #if OS_WINDOWS os = OperatingSystem_Windows; #elif OS_LINUX os = OperatingSystem_Linux; #elif OS_MAC os = OperatingSystem_Mac; #endif return os; } internal Arch arch_from_context(void){ Arch arch = Arch_Null; #if ARCH_X64 arch = Arch_x64; #elif ARCH_X86 arch = Arch_x86; #elif ARCH_ARM64 arch = Arch_arm64; #elif ARCH_ARM32 arch = Arch_arm32; #endif return arch; } internal Compiler compiler_from_context(void){ Compiler compiler = Compiler_Null; #if COMPILER_MSVC compiler = Compiler_msvc; #elif COMPILER_GCC compiler = Compiler_gcc; #elif COMPILER_CLANG compiler = Compiler_clang; #endif return compiler; } //////////////////////////////// //~ 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; }