diff --git a/math/module.jai b/math/module.jai index 3e69b01..4236cea 100644 --- a/math/module.jai +++ b/math/module.jai @@ -3,6 +3,21 @@ RUN_TESTS := false ); +// @todo(judah): dumb we can't use meta.range_for here. + +U8_Min, U8_Max :: #run meta.lo_for(u8), #run meta.hi_for(u8); +U16_Min, U16_Max :: #run meta.lo_for(u16), #run meta.hi_for(u16); +U32_Min, U32_Max :: #run meta.lo_for(u32), #run meta.hi_for(u32); +U64_Min, U64_Max :: #run meta.lo_for(u64), #run meta.hi_for(u64); + +S8_Min, S8_Max :: #run meta.lo_for(s8), #run meta.hi_for(s8); +S16_Min, S16_Max :: #run meta.lo_for(s16), #run meta.hi_for(s16); +S32_Min, S32_Max :: #run meta.lo_for(s32), #run meta.hi_for(s32); +S64_Min, S64_Max :: #run meta.lo_for(s64), #run meta.hi_for(s64); + +F32_Min, F32_Max :: #run meta.lo_for(float32), #run meta.hi_for(float32); +F64_Min, F64_Max :: #run meta.lo_for(float64), #run meta.hi_for(float64); + #load "vec.jai"; #load "mat.jai"; #load "ease.jai"; @@ -19,9 +34,11 @@ bounds_check_index :: ($$idx: int, $count: int, loc := #caller_location) #expand } } - -basic :: #import "Basic"; // @future - #if RUN_TESTS { test :: #import "jc/test"; } + +#scope_file; + +meta :: #import "jc/meta"; +basic :: #import "Basic"; // @future diff --git a/math/vec.jai b/math/vec.jai index 7430b34..8227cf1 100644 --- a/math/vec.jai +++ b/math/vec.jai @@ -354,3 +354,4 @@ quat :: (x: float = 0, y: float = 0, z: float = 0, w: float = 0) -> Quat #expand meta :: #import "jc/meta"; math :: #import "Math"; // @future +basic :: #import "Basic"; // @future diff --git a/meta/type_info.jai b/meta/type_info.jai index d7d4637..0bafc45 100644 --- a/meta/type_info.jai +++ b/meta/type_info.jai @@ -43,38 +43,198 @@ type_is_enum :: ($$T: Type) -> bool, *Type_Info_Enum { return ok, info.(*Type_Info_Enum); } -enum_min :: (T: Type) -> int #expand { - return #run -> int { - ok, info := type_is_enum(T); - assert(ok, "type given to enum_min must be an enum"); +// Returns the lowest and highest values T can represent. +// Note: T must be an integer, float, or enum type. +range_for :: ($T: Type, loc := #caller_location) -> (T, T) #expand { + // @note(judah): we need to runs here because jai is weird. + return #run lo_for(T, loc = loc), #run hi_for(T, loc = loc); +} - if info.values.count == 0 { - return 0; +// Returns the lowest value T can represent. +// Note: T must be an integer, float, or enum type. +lo_for :: ($T: Type, loc := #caller_location) -> T #expand { + return #run -> T { + info := T.(*Type_Info); + if info.type == { + case .INTEGER; + i := info.(*Type_Info_Integer); + if i.runtime_size == { + case 1; return (ifx i.signed then -0x80 else 0).(T, no_check); + case 2; return (ifx i.signed then -0x8000 else 0).(T, no_check); + case 4; return (ifx i.signed then -0x8000_0000 else 0).(T, no_check); + case 8; return (ifx i.signed then -0x8000_0000_0000_0000 else 0).(T, no_check); + case; + compiler.compiler_report("unhandled integer type", loc = loc); + } + + case .FLOAT; + if info.runtime_size == { + case 4; return (0h00800000).(T, no_check); + case 8; return (0h00100000_00000000).(T, no_check); + case; + compiler.compiler_report("unhandled float type", loc = loc); + } + + case .ENUM; + i := info.(*Type_Info_Enum); + if i.values.count == 0 { + return 0; + } + + min: T = i.values[0].(T, no_check); + if i.internal_type.signed { + for i.values if it.(T) < min { + min = it.(T); + } + } + else { + for i.values if it.(T) < min { + min = it.(T); + } + } + + return min; + + case; + compiler.compiler_report("min requires an enum, integer, or float type", loc = loc); } - min := 0xFFFFFF_FFFFFF; - for info.values if it < min { - min = it; - } - - return min; + return 0; }; } -enum_max :: (T: Type) -> int #expand { - return #run -> int { - ok, info := type_is_enum(T); - assert(ok, "type given to enum_max must be an enum"); +// Returns the highest value T can represent. +// Note: T must be an integer, float, or enum type. +hi_for :: ($T: Type, loc := #caller_location) -> T #expand { + return #run -> T { + info := T.(*Type_Info); + if info.type == { + case .INTEGER; + i := info.(*Type_Info_Integer); + if i.runtime_size == { + case 1; return (ifx i.signed then 0x7f else 0xff).(T, no_check); + case 2; return (ifx i.signed then 0x7fff else 0xffff).(T, no_check); + case 4; return (ifx i.signed then 0x7fff_ffff else 0xffff_ffff).(T, no_check); + case 8; return (ifx i.signed then 0x7fff_ffff_ffff_ffff else 0xffff_ffff_ffff_ffff).(T, no_check); + case; + compiler.compiler_report("unhandled integer type", loc = loc); + } - if info.values.count == 0 { - return 0; + case .FLOAT; + if info.runtime_size == { + case 4; return (0h7F7FFFFF).(T, no_check); + case 8; return (0h7FEFFFFF_FFFFFFFF).(T, no_check); + case; + compiler.compiler_report("unhandled float type", loc = loc); + } + + case .ENUM; + i := info.(*Type_Info_Enum); + if i.values.count == 0 { + return 0; + } + + max := i.values[0].(T, no_check); + if i.internal_type.signed { + for i.values if xx it > max { + max = xx it; + } + } + else { + for i.values if xx it > max { + max = xx it; + } + } + + return max; + + case; + compiler.compiler_report("max requires an enum, integer, or float type", loc = loc); } - max := 0; - for info.values if it > max { - max = it; - } - - return max; + return 0; }; } + + +#scope_file; + +compiler :: #import "Compiler"; // @future + + +// ---------------------------------------------------------- +// TESTS +// ---------------------------------------------------------- + +#if RUN_TESTS #run { + test.run("lo_for:primitives", t => { + test.expect(t, lo_for(u8) == 0); + test.expect(t, lo_for(s8) == -128); + test.expect(t, lo_for(u16) == 0); + test.expect(t, lo_for(s16) == -32768); + test.expect(t, lo_for(u32) == 0); + test.expect(t, lo_for(s32) == -2147483648); + test.expect(t, lo_for(u64) == 0); + test.expect(t, lo_for(s64) == -9223372036854775808); + + test.expect(t, lo_for(float32) == 0h00800000); + test.expect(t, lo_for(float64) == 0h00100000_00000000); + }); + + test.run("hi_for:primitives", t => { + test.expect(t, hi_for(u8) == 255); + test.expect(t, hi_for(s8) == 127); + test.expect(t, hi_for(u16) == 65535); + test.expect(t, hi_for(s16) == 32767); + test.expect(t, hi_for(u32) == 4294967295); + test.expect(t, hi_for(s32) == 2147483647); + test.expect(t, hi_for(u64) == 18446744073709551615); + test.expect(t, hi_for(s64) == 9223372036854775807); + + test.expect(t, hi_for(float32) == 340282346638528859000000000000000000000.0); + test.expect(t, hi_for(float64) == 179769313486231570900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0); + }); + + test.run("lo_for/hi_for:enums", t => { + U8_Enum :: enum u8 { lo :: -1; hi :: +1; } + S8_Enum :: enum s8 { lo :: -2; hi :: -1; } + { + test.expect(t, lo_for(U8_Enum) == U8_Enum.lo); + test.expect(t, lo_for(S8_Enum) == S8_Enum.lo); + test.expect(t, hi_for(U8_Enum) == U8_Enum.hi); + test.expect(t, hi_for(S8_Enum) == S8_Enum.hi); + } + + U16_Enum :: enum u16 { lo :: -1; hi :: +1; } + S16_Enum :: enum s16 { lo :: -2; hi :: -1; } + { + test.expect(t, lo_for(U16_Enum) == U16_Enum.lo); + test.expect(t, lo_for(S16_Enum) == S16_Enum.lo); + test.expect(t, hi_for(U16_Enum) == U16_Enum.hi); + test.expect(t, hi_for(S16_Enum) == S16_Enum.hi); + } + + U32_Enum :: enum u32 { lo :: -1; hi :: +1; } + S32_Enum :: enum s32 { lo :: -2; hi :: -1; } + { + test.expect(t, lo_for(U32_Enum) == U32_Enum.lo); + test.expect(t, lo_for(S32_Enum) == S32_Enum.lo); + test.expect(t, hi_for(U32_Enum) == U32_Enum.hi); + test.expect(t, hi_for(S32_Enum) == S32_Enum.hi); + } + + U64_Enum :: enum u64 { lo :: -1; hi :: +1; } + S64_Enum :: enum s64 { lo :: -2; hi :: -1; } + { + test.expect(t, lo_for(U64_Enum) == U64_Enum.lo); + test.expect(t, lo_for(S64_Enum) == S64_Enum.lo); + test.expect(t, hi_for(U64_Enum) == U64_Enum.hi); + test.expect(t, hi_for(S64_Enum) == S64_Enum.hi); + } + + // @note(judah): just making sure this compiles + lo, hi := range_for(U64_Enum); + test.expect(t, lo == U64_Enum.lo); + test.expect(t, hi == U64_Enum.hi); + }); +}