aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/runtime/core.odin7
-rw-r--r--base/runtime/random_generator.odin64
2 files changed, 70 insertions, 1 deletions
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