1package rand
2
3import (
4	"math/rand"
5	"sync"
6)
7
8// LockedRand implements NumberGenerator and embeds Rand that is safe for concurrent use.
9type LockedRand struct {
10	lk sync.Mutex
11	r  *rand.Rand
12}
13
14// NewLockedRand creates a new LockedRand that implements all Rand functions that is safe
15// for concurrent use.
16func NewLockedRand(seed int64) *LockedRand {
17	return &LockedRand{
18		r: rand.New(rand.NewSource(seed)),
19	}
20}
21
22// Seed uses the provided seed value to initialize the generator to a deterministic state.
23// Seed should not be called concurrently with any other Rand method.
24func (lr *LockedRand) Seed(seed int64) {
25	lr.lk.Lock()
26	lr.r.Seed(seed)
27	lr.lk.Unlock()
28}
29
30// TwoInt63 generates 2 random int64 without locking twice.
31func (lr *LockedRand) TwoInt63() (n1, n2 int64) {
32	lr.lk.Lock()
33	n1 = lr.r.Int63()
34	n2 = lr.r.Int63()
35	lr.lk.Unlock()
36	return
37}
38
39// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
40func (lr *LockedRand) Int63() (n int64) {
41	lr.lk.Lock()
42	n = lr.r.Int63()
43	lr.lk.Unlock()
44	return
45}
46
47// Uint32 returns a pseudo-random 32-bit value as a uint32.
48func (lr *LockedRand) Uint32() (n uint32) {
49	lr.lk.Lock()
50	n = lr.r.Uint32()
51	lr.lk.Unlock()
52	return
53}
54
55// Uint64 returns a pseudo-random 64-bit value as a uint64.
56func (lr *LockedRand) Uint64() (n uint64) {
57	lr.lk.Lock()
58	n = lr.r.Uint64()
59	lr.lk.Unlock()
60	return
61}
62
63// TwoUint64 generates 2 random uint64 without locking twice.
64func (lr *LockedRand) TwoUint64()  (n1, n2 uint64) {
65	lr.lk.Lock()
66	n1 = lr.r.Uint64()
67	n2 = lr.r.Uint64()
68	lr.lk.Unlock()
69	return
70}
71
72// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
73func (lr *LockedRand) Int31() (n int32) {
74	lr.lk.Lock()
75	n = lr.r.Int31()
76	lr.lk.Unlock()
77	return
78}
79
80// Int returns a non-negative pseudo-random int.
81func (lr *LockedRand) Int() (n int) {
82	lr.lk.Lock()
83	n = lr.r.Int()
84	lr.lk.Unlock()
85	return
86}
87
88// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
89// It panics if n <= 0.
90func (lr *LockedRand) Int63n(n int64) (r int64) {
91	lr.lk.Lock()
92	r = lr.r.Int63n(n)
93	lr.lk.Unlock()
94	return
95}
96
97// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
98// It panics if n <= 0.
99func (lr *LockedRand) Int31n(n int32) (r int32) {
100	lr.lk.Lock()
101	r = lr.r.Int31n(n)
102	lr.lk.Unlock()
103	return
104}
105
106// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
107// It panics if n <= 0.
108func (lr *LockedRand) Intn(n int) (r int) {
109	lr.lk.Lock()
110	r = lr.r.Intn(n)
111	lr.lk.Unlock()
112	return
113}
114
115// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
116func (lr *LockedRand) Float64() (n float64) {
117	lr.lk.Lock()
118	n = lr.r.Float64()
119	lr.lk.Unlock()
120	return
121}
122
123// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
124func (lr *LockedRand) Float32() (n float32) {
125	lr.lk.Lock()
126	n = lr.r.Float32()
127	lr.lk.Unlock()
128	return
129}
130
131// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
132func (lr *LockedRand) Perm(n int) (r []int) {
133	lr.lk.Lock()
134	r = lr.r.Perm(n)
135	lr.lk.Unlock()
136	return
137}
138
139// Read generates len(p) random bytes and writes them into p. It
140// always returns len(p) and a nil error.
141// Read should not be called concurrently with any other Rand method.
142func (lr *LockedRand) Read(p []byte) (n int, err error) {
143	lr.lk.Lock()
144	n, err = lr.r.Read(p)
145	lr.lk.Unlock()
146	return
147}
148