mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
677 lines
14 KiB
C
677 lines
14 KiB
C
// 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
|
|
# define STB_SPRINTF_IMPLEMENTATION
|
|
# include "third_party/stb/stb_sprintf.h"
|
|
#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,
|
|
};
|