| OLD | NEW |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package mathrand | 5 package mathrand |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "math/rand" | 8 "math/rand" |
| 9 "sync" | 9 "sync" |
| 10 ) | 10 ) |
| 11 | 11 |
| 12 // Rand is a random number generator interface. | 12 // Rand is a random number generator interface. |
| 13 // | 13 // |
| 14 // A Rand instance is not necessarily safe for concurrent use. In order to | 14 // A Rand instance is not necessarily safe for concurrent use. In order to |
| 15 // ensure that it is, wrap it in Locking or obtain it from a method that | 15 // ensure that it is, wrap it in Locking or obtain it from a method that |
| 16 // provides this guarantee (e.g., Get). | 16 // provides this guarantee (e.g., Get). |
| 17 // |
| 18 // All Rand functions MUST NOT PANIC. In particular, the Locking implementation |
| 19 // relies on embedded methods not panicking in order to release its lock, and |
| 20 // a panic will cause it to hold its lock indefinitely. |
| 17 type Rand interface { | 21 type Rand interface { |
| 18 // Int63 returns a non-negative pseudo-random 63-bit integer as an int64 | 22 // Int63 returns a non-negative pseudo-random 63-bit integer as an int64 |
| 19 // from the source in the context or the shared global source. | 23 // from the source in the context or the shared global source. |
| 20 Int63() int64 | 24 Int63() int64 |
| 21 | 25 |
| 22 // Uint32 returns a pseudo-random 32-bit value as a uint32 from the sour
ce in | 26 // Uint32 returns a pseudo-random 32-bit value as a uint32 from the sour
ce in |
| 23 // the context or the shared global source. | 27 // the context or the shared global source. |
| 24 Uint32() uint32 | 28 Uint32() uint32 |
| 25 | 29 |
| 26 // Int31 returns a non-negative pseudo-random 31-bit integer as an int32
from | 30 // Int31 returns a non-negative pseudo-random 31-bit integer as an int32
from |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 // the output using: | 91 // the output using: |
| 88 // | 92 // |
| 89 // sample = ExpFloat64(ctx) / desiredRateParameter | 93 // sample = ExpFloat64(ctx) / desiredRateParameter |
| 90 // | 94 // |
| 91 ExpFloat64() float64 | 95 ExpFloat64() float64 |
| 92 | 96 |
| 93 // WithGoRand invokes the supplied "fn" while holding an exclusive lock | 97 // WithGoRand invokes the supplied "fn" while holding an exclusive lock |
| 94 // for it. This can be used by callers to pull and use a *rand.Rand inst
ance | 98 // for it. This can be used by callers to pull and use a *rand.Rand inst
ance |
| 95 // out of the Context safely. | 99 // out of the Context safely. |
| 96 // | 100 // |
| 101 // Other "mathrand" functions and objects MUST NOT BE USED inside the |
| 102 // callback, as WithGoRand holds the lock to the current Rand instance,
so any |
| 103 // additional function call will deadlock. |
| 104 // |
| 97 // The callback's r must not be retained or used outside of hte scope of
the | 105 // The callback's r must not be retained or used outside of hte scope of
the |
| 98 // callback. | 106 // callback. |
| 99 WithGoRand(fn func(r *rand.Rand) error) error | 107 WithGoRand(fn func(r *rand.Rand) error) error |
| 100 } | 108 } |
| 101 | 109 |
| 102 // Locking wraps a Rand instance in a layer that locks around all of its | 110 // Locking wraps a Rand instance in a layer that locks around all of its |
| 103 // methods. | 111 // methods. |
| 104 // | 112 // |
| 105 // A user must hold Locking's Mutex if the want to directly access and use | 113 // A user must hold Locking's Mutex if the want to directly access and use |
| 106 // Locking's R member safely. | 114 // Locking's R member safely. |
| 107 // | 115 // |
| 108 // By default, a Rand instance is not safe for concurrent use. A ocking Rand | 116 // By default, a Rand instance is not safe for concurrent use. A ocking Rand |
| 109 // instance is. | 117 // instance is. |
| 110 type Locking struct { | 118 type Locking struct { |
| 111 sync.Mutex | 119 sync.Mutex |
| 112 R Rand | 120 R Rand |
| 113 } | 121 } |
| 114 | 122 |
| 115 func wrapLocking(r Rand) Rand { | 123 func wrapLocking(r Rand) Rand { |
| 116 if _, ok := r.(*Locking); ok { | 124 if _, ok := r.(*Locking); ok { |
| 117 return r | 125 return r |
| 118 } | 126 } |
| 119 return &Locking{R: r} | 127 return &Locking{R: r} |
| 120 } | 128 } |
| 121 | 129 |
| 122 // Int63 returns a non-negative pseudo-random 63-bit integer as an int64 | 130 // Int63 returns a non-negative pseudo-random 63-bit integer as an int64 |
| 123 // from the source in the context or the shared global source. | 131 // from the source in the context or the shared global source. |
| 124 func (l *Locking) Int63() int64 { | 132 func (l *Locking) Int63() (v int64) { |
| 125 l.Lock() | 133 l.Lock() |
| 126 » defer l.Unlock() | 134 » v = l.R.Int63() |
| 127 » return l.R.Int63() | 135 » l.Unlock() |
| 136 » return |
| 128 } | 137 } |
| 129 | 138 |
| 130 // Uint32 returns a pseudo-random 32-bit value as a uint32 from the source in | 139 // Uint32 returns a pseudo-random 32-bit value as a uint32 from the source in |
| 131 // the context or the shared global source. | 140 // the context or the shared global source. |
| 132 func (l *Locking) Uint32() uint32 { | 141 func (l *Locking) Uint32() (v uint32) { |
| 133 l.Lock() | 142 l.Lock() |
| 134 » defer l.Unlock() | 143 » v = l.R.Uint32() |
| 135 » return l.R.Uint32() | 144 » l.Unlock() |
| 145 » return |
| 136 } | 146 } |
| 137 | 147 |
| 138 // Int31 returns a non-negative pseudo-random 31-bit integer as an int32 from | 148 // Int31 returns a non-negative pseudo-random 31-bit integer as an int32 from |
| 139 // the source in the context or the shared global source. | 149 // the source in the context or the shared global source. |
| 140 func (l *Locking) Int31() int32 { | 150 func (l *Locking) Int31() (v int32) { |
| 141 l.Lock() | 151 l.Lock() |
| 142 » defer l.Unlock() | 152 » v = l.R.Int31() |
| 143 » return l.R.Int31() | 153 » l.Unlock() |
| 154 » return |
| 144 } | 155 } |
| 145 | 156 |
| 146 // Int returns a non-negative pseudo-random int from the source in the context | 157 // Int returns a non-negative pseudo-random int from the source in the context |
| 147 // or the shared global source. | 158 // or the shared global source. |
| 148 func (l *Locking) Int() int { | 159 func (l *Locking) Int() (v int) { |
| 149 l.Lock() | 160 l.Lock() |
| 150 » defer l.Unlock() | 161 » v = l.R.Int() |
| 151 » return l.R.Int() | 162 » l.Unlock() |
| 163 » return |
| 152 } | 164 } |
| 153 | 165 |
| 154 // Int63n returns, as an int64, a non-negative pseudo-random number in [0,n) | 166 // Int63n returns, as an int64, a non-negative pseudo-random number in [0,n) |
| 155 // from the source in the context or the shared global source. | 167 // from the source in the context or the shared global source. |
| 156 // | 168 // |
| 157 // It panics if n <= 0. | 169 // It panics if n <= 0. |
| 158 func (l *Locking) Int63n(n int64) int64 { | 170 func (l *Locking) Int63n(n int64) (v int64) { |
| 159 l.Lock() | 171 l.Lock() |
| 160 » defer l.Unlock() | 172 » v = l.R.Int63n(n) |
| 161 » return l.R.Int63n(n) | 173 » l.Unlock() |
| 174 » return |
| 162 } | 175 } |
| 163 | 176 |
| 164 // Int31n returns, as an int32, a non-negative pseudo-random number in [0,n) | 177 // Int31n returns, as an int32, a non-negative pseudo-random number in [0,n) |
| 165 // from the source in the context or the shared global source. | 178 // from the source in the context or the shared global source. |
| 166 // | 179 // |
| 167 // It panics if n <= 0. | 180 // It panics if n <= 0. |
| 168 func (l *Locking) Int31n(n int32) int32 { | 181 func (l *Locking) Int31n(n int32) (v int32) { |
| 169 l.Lock() | 182 l.Lock() |
| 170 » defer l.Unlock() | 183 » v = l.R.Int31n(n) |
| 171 » return l.R.Int31n(n) | 184 » l.Unlock() |
| 185 » return |
| 172 } | 186 } |
| 173 | 187 |
| 174 // Intn returns, as an int, a non-negative pseudo-random number in [0,n) from | 188 // Intn returns, as an int, a non-negative pseudo-random number in [0,n) from |
| 175 // the source in the context or the shared global source. | 189 // the source in the context or the shared global source. |
| 176 // | 190 // |
| 177 // It panics if n <= 0. | 191 // It panics if n <= 0. |
| 178 func (l *Locking) Intn(n int) int { | 192 func (l *Locking) Intn(n int) (v int) { |
| 179 l.Lock() | 193 l.Lock() |
| 180 » defer l.Unlock() | 194 » v = l.R.Intn(n) |
| 181 » return l.R.Intn(n) | 195 » l.Unlock() |
| 196 » return |
| 182 } | 197 } |
| 183 | 198 |
| 184 // Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from | 199 // Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from |
| 185 // the source in the context or the shared global source. | 200 // the source in the context or the shared global source. |
| 186 func (l *Locking) Float64() float64 { | 201 func (l *Locking) Float64() (v float64) { |
| 187 l.Lock() | 202 l.Lock() |
| 188 » defer l.Unlock() | 203 » v = l.R.Float64() |
| 189 » return l.R.Float64() | 204 » l.Unlock() |
| 205 » return |
| 190 } | 206 } |
| 191 | 207 |
| 192 // Float32 returns, as a float32, a pseudo-random number in [0.0,1.0) from | 208 // Float32 returns, as a float32, a pseudo-random number in [0.0,1.0) from |
| 193 // the source in the context or the shared global source. | 209 // the source in the context or the shared global source. |
| 194 func (l *Locking) Float32() float32 { | 210 func (l *Locking) Float32() (v float32) { |
| 195 l.Lock() | 211 l.Lock() |
| 196 » defer l.Unlock() | 212 » v = l.R.Float32() |
| 197 » return l.R.Float32() | 213 » l.Unlock() |
| 214 » return |
| 198 } | 215 } |
| 199 | 216 |
| 200 // Perm returns, as a slice of n ints, a pseudo-random permutation of the | 217 // Perm returns, as a slice of n ints, a pseudo-random permutation of the |
| 201 // integers [0,n) from the source in the context or the shared global source. | 218 // integers [0,n) from the source in the context or the shared global source. |
| 202 func (l *Locking) Perm(n int) []int { | 219 func (l *Locking) Perm(n int) (v []int) { |
| 203 l.Lock() | 220 l.Lock() |
| 204 » defer l.Unlock() | 221 » v = l.R.Perm(n) |
| 205 » return l.R.Perm(n) | 222 » l.Unlock() |
| 223 » return |
| 206 } | 224 } |
| 207 | 225 |
| 208 // Read generates len(p) random bytes from the source in the context or | 226 // Read generates len(p) random bytes from the source in the context or |
| 209 // the shared global source and writes them into p. It always returns len(p) | 227 // the shared global source and writes them into p. It always returns len(p) |
| 210 // and a nil error. | 228 // and a nil error. |
| 211 func (l *Locking) Read(p []byte) (n int, err error) { | 229 func (l *Locking) Read(p []byte) (n int, err error) { |
| 212 l.Lock() | 230 l.Lock() |
| 213 » defer l.Unlock() | 231 » n, err = l.R.Read(p) |
| 214 » return l.R.Read(p) | 232 » l.Unlock() |
| 233 » return |
| 215 } | 234 } |
| 216 | 235 |
| 217 // NormFloat64 returns a normally distributed float64 in the range | 236 // NormFloat64 returns a normally distributed float64 in the range |
| 218 // [-math.MaxFloat64, +math.MaxFloat64] with standard normal distribution | 237 // [-math.MaxFloat64, +math.MaxFloat64] with standard normal distribution |
| 219 // (mean = 0, stddev = 1) from the source in the context or the shared global | 238 // (mean = 0, stddev = 1) from the source in the context or the shared global |
| 220 // source. | 239 // source. |
| 221 // | 240 // |
| 222 // To produce a different normal distribution, callers can adjust the output | 241 // To produce a different normal distribution, callers can adjust the output |
| 223 // using: | 242 // using: |
| 224 // | 243 // |
| 225 // sample = NormFloat64(ctx) * desiredStdDev + desiredMean | 244 // sample = NormFloat64(ctx) * desiredStdDev + desiredMean |
| 226 // | 245 // |
| 227 func (l *Locking) NormFloat64() float64 { | 246 func (l *Locking) NormFloat64() (v float64) { |
| 228 l.Lock() | 247 l.Lock() |
| 229 » defer l.Unlock() | 248 » v = l.R.NormFloat64() |
| 230 » return l.R.NormFloat64() | 249 » l.Unlock() |
| 250 » return |
| 231 } | 251 } |
| 232 | 252 |
| 233 // ExpFloat64 returns an exponentially distributed float64 in the range | 253 // ExpFloat64 returns an exponentially distributed float64 in the range |
| 234 // (0, +math.MaxFloat64] with an exponential distribution whose rate parameter | 254 // (0, +math.MaxFloat64] with an exponential distribution whose rate parameter |
| 235 // (lambda) is 1 and whose mean is 1/lambda (1) from the source in the context | 255 // (lambda) is 1 and whose mean is 1/lambda (1) from the source in the context |
| 236 // or the shared global source. | 256 // or the shared global source. |
| 237 // | 257 // |
| 238 // To produce a distribution with a different rate parameter, callers can adjust | 258 // To produce a distribution with a different rate parameter, callers can adjust |
| 239 // the output using: | 259 // the output using: |
| 240 // | 260 // |
| 241 // sample = ExpFloat64(ctx) / desiredRateParameter | 261 // sample = ExpFloat64(ctx) / desiredRateParameter |
| 242 // | 262 // |
| 243 func (l *Locking) ExpFloat64() float64 { | 263 func (l *Locking) ExpFloat64() (v float64) { |
| 244 l.Lock() | 264 l.Lock() |
| 245 » defer l.Unlock() | 265 » v = l.R.ExpFloat64() |
| 246 » return l.R.ExpFloat64() | 266 » l.Unlock() |
| 267 » return |
| 247 } | 268 } |
| 248 | 269 |
| 249 // WithGoRand invokes the supplied "fn" while holding an exclusive lock | 270 // WithGoRand invokes the supplied "fn" while holding an exclusive lock |
| 250 // for it. This can be used by callers to pull and use a *rand.Rand instance | 271 // for it. This can be used by callers to pull and use a *rand.Rand instance |
| 251 // out of the Context safely. | 272 // out of the Context safely. |
| 252 // | 273 // |
| 253 // The callback's r must not be retained or used outside of hte scope of the | 274 // The callback's r must not be retained or used outside of the scope of the |
| 254 // callback. | 275 // callback. |
| 255 func (l *Locking) WithGoRand(fn func(r *rand.Rand) error) error { | 276 func (l *Locking) WithGoRand(fn func(r *rand.Rand) error) error { |
| 256 l.Lock() | 277 l.Lock() |
| 257 defer l.Unlock() | 278 defer l.Unlock() |
| 258 return l.R.WithGoRand(fn) | 279 return l.R.WithGoRand(fn) |
| 259 } | 280 } |
| 260 | 281 |
| 261 // wrapped is a simple wrapper to a *math.Rand instance. | 282 // wrapped is a simple wrapper to a *math.Rand instance. |
| 262 type wrapped struct { | 283 type wrapped struct { |
| 263 *rand.Rand | 284 *rand.Rand |
| 264 } | 285 } |
| 265 | 286 |
| 266 // Wrap wraps a Rand instance, allowing it to satisfy the Rand interface. | 287 // Wrap wraps a Rand instance, allowing it to satisfy the Rand interface. |
| 267 func wrapRand(r *rand.Rand) Rand { return wrapped{r} } | 288 func wrapRand(r *rand.Rand) Rand { return wrapped{r} } |
| 268 | 289 |
| 269 func (w wrapped) WithGoRand(fn func(r *rand.Rand) error) error { return fn(w.Ran
d) } | 290 func (w wrapped) WithGoRand(fn func(r *rand.Rand) error) error { return fn(w.Ran
d) } |
| OLD | NEW |