diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 9669e86aa..a4a433d94 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -410,8 +410,10 @@ Random_Generator_Query_Info_Flag :: enum u32 { } Random_Generator_Query_Info :: distinct bit_set[Random_Generator_Query_Info_Flag; u32] +Random_Generator_Proc :: #type proc(data: rawptr, mode: Random_Generator_Mode, p: []byte) + Random_Generator :: struct { - procedure: proc(data: rawptr, mode: Random_Generator_Mode, p: []byte), + procedure: Random_Generator_Proc, data: rawptr, } @@ -727,6 +729,9 @@ __init_context :: proc "contextless" (c: ^Context) { c.logger.procedure = default_logger_proc c.logger.data = nil + + c.random_generator.procedure = default_random_generator_proc + c.random_generator.data = nil } default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! { diff --git a/base/runtime/random_generator.odin b/base/runtime/random_generator.odin index 2b66b3e0b..7746f1429 100644 --- a/base/runtime/random_generator.odin +++ b/base/runtime/random_generator.odin @@ -1,5 +1,7 @@ package runtime +import "base:intrinsics" + @(require_results) random_generator_read_bytes :: proc(rg: Random_Generator, p: []byte) -> bool { if rg.procedure != nil { @@ -24,4 +26,66 @@ random_generator_query_info :: proc(rg: Random_Generator) -> (info: Random_Gener rg.procedure(rg.data, .Query_Info, ([^]byte)(&info)[:size_of(info)]) } return +} + + +@(private="file") +Default_Random_State :: struct { + state: u64, + inc: u64, +} + +default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode, p: []byte) { + @(require_results) + read_u64 :: proc "contextless" (r: ^Default_Random_State) -> u64 { + old_state := r.state + r.state = old_state * 6364136223846793005 + (r.inc|1) + xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081 + rot := (old_state >> 59) + return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63)) + } + + @(thread_local) + global_rand_seed: Default_Random_State + + switch mode { + case .Read: + r := &global_rand_seed + + if r.state == 0 && + r.inc == 0 { + seed := u64(intrinsics.read_cycle_counter()) + r.state = 0 + r.inc = (seed << 1) | 1 + _ = read_u64(r) + r.state += seed + _ = read_u64(r) + } + + pos := i8(0) + val := u64(0) + for &v in p { + if pos == 0 { + val = read_u64(r) + pos = 7 + } + v = byte(val) + val >>= 8 + pos -= 1 + } + return + case .Query_Info: + if len(p) != size_of(Random_Generator_Query_Info) { + return + } + info := (^Random_Generator_Query_Info)(raw_data(p)) + info^ += {.Uniform} + } +} + +default_random_generator :: proc "contextless" () -> Random_Generator { + return { + procedure = default_random_generator_proc, + data = nil, + } } \ No newline at end of file