-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfastrand.odin
More file actions
117 lines (100 loc) · 2.62 KB
/
Copy pathfastrand.odin
File metadata and controls
117 lines (100 loc) · 2.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package fastrand
import "base:intrinsics"
import "base:runtime"
import "core:math/rand"
// Constants taken from https://github.com/wangyi-fudan/wyhash/blob/46cebe9dc4e51f94d0dca287733bc5a94f76a10d/wyhash.h#L151
ADDITIVE_CONST :: 0x2d358dccaa6c78a5
MIXING_CONST :: 0x8bb84b93962eacc9
// The state
Random_State :: struct {
s: u64,
}
// Returns an instance of the pseudorandom generator
@(require_results)
random_generator :: proc "contextless" (state: ^Random_State = nil) -> rand.Generator {
return rand.Generator{
procedure = random_generator_proc,
data = state,
}
}
// Random procedure for rand.Generator
@(private)
random_generator_proc :: proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []u8) {
@(thread_local)
global_rand_seed: Random_State
r: ^Random_State = ---
if data == nil {
r = &global_rand_seed
} else {
r = cast(^Random_State)data
}
switch mode {
case .Read:
// fill_bytes(r, p)
// Fast path for a 64-bit destination.
buf_len := len(p)
if buf_len == size_of(u64) {
val := gen_u64(r)
intrinsics.unaligned_store((^u64)(raw_data(p)), val)
return
}
i := 0
for i + 8 <= buf_len {
val := gen_u64(r)
#no_bounds_check {
intrinsics.unaligned_store((^u64)(&p[i]), val)
}
i += 8
}
if i < buf_len {
val := gen_u64(r)
#no_bounds_check {
runtime.mem_copy_non_overlapping(&p[i], &val, buf_len - i)
}
}
case .Reset:
seed: u64
runtime.mem_copy_non_overlapping(&seed, raw_data(p), min(size_of(seed), len(p)))
r.s = seed
case .Query_Info:
info := (^rand.Generator_Query_Info)(raw_data(p))
info^ += {.Uniform, .Resettable}
}
}
@(require_results)
wrapping_add :: #force_inline proc "contextless" (a, b: u64) -> u64 {
return a + b
}
// Generate next u64
@(require_results)
gen_u64 :: proc "contextless" (r: ^Random_State) -> u64 {
r.s = wrapping_add(r.s, ADDITIVE_CONST)
prod := u128(r.s) * u128(r.s ~ MIXING_CONST)
hi := u64(prod >> 64)
lo := u64(prod)
return hi ~ lo
}
// Fill buffer with random bytes
fill_bytes :: #force_inline proc "contextless" (r: ^Random_State, buf: []byte) {
// Fast path for a 64-bit destination.
buf_len := len(buf)
if buf_len == size_of(u64) {
val := gen_u64(r)
intrinsics.unaligned_store((^u64)(raw_data(buf)), val)
return
}
i := 0
for i + 8 <= buf_len {
val := gen_u64(r)
#no_bounds_check {
intrinsics.unaligned_store((^u64)(&buf[i]), val)
}
i += 8
}
if i < buf_len {
val := gen_u64(r)
#no_bounds_check {
runtime.mem_copy_non_overlapping(&buf[i], &val, buf_len - i)
}
}
}