]> Cypherpunks repositories - gostls13.git/commitdiff
math/rand: refactor to delay allocation of global source
authorRuss Cox <rsc@golang.org>
Tue, 4 Oct 2022 15:24:47 +0000 (11:24 -0400)
committerGopher Robot <gobot@golang.org>
Tue, 18 Oct 2022 14:49:46 +0000 (14:49 +0000)
This sets up for delaying the decision of which seed to use,
but this CL still keeps the original global Seed(1) semantics.

Preparation for #54880.

Change-Id: Ibfa9d50ec9023aa755a83852e55168fa7d24b115
Reviewed-on: https://go-review.googlesource.com/c/go/+/443057
Auto-Submit: Russ Cox <rsc@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>

src/math/rand/rand.go

index bcf2f9c950526e48bf42bb2566161d90bccb1cb5..4627d4515fb391cd9109995609d36f4120226f33 100644 (file)
@@ -42,10 +42,10 @@ type Source64 interface {
 // safe for concurrent use by multiple goroutines.
 // The returned Source implements Source64.
 func NewSource(seed int64) Source {
-       return newSource64(seed)
+       return newSource(seed)
 }
 
-func newSource64(seed int64) Source64 {
+func newSource(seed int64) *rngSource {
        var rng rngSource
        rng.Seed(seed)
        return &rng
@@ -295,10 +295,7 @@ func read(p []byte, src Source, readVal *int64, readPos *int8) (n int, err error
  * Top-level convenience functions
  */
 
-var globalRand = New(&lockedSource{src: NewSource(1).(*rngSource)})
-
-// Type assert that globalRand's source is a lockedSource whose src is a *rngSource.
-var _ *rngSource = globalRand.src.(*lockedSource).src
+var globalRand = New(new(lockedSource))
 
 // Seed uses the provided seed value to initialize the default Source to a
 // deterministic state. If Seed is not called, the generator behaves as
@@ -383,42 +380,61 @@ func NormFloat64() float64 { return globalRand.NormFloat64() }
 func ExpFloat64() float64 { return globalRand.ExpFloat64() }
 
 type lockedSource struct {
-       lk  sync.Mutex
-       src *rngSource
+       lk sync.Mutex
+       s  *rngSource // nil if not yet allocated
+}
+
+// source returns r.s, allocating and seeding it if needed.
+// The caller must have locked r.
+func (r *lockedSource) source() *rngSource {
+       if r.s == nil {
+               r.s = newSource(1)
+       }
+       return r.s
 }
 
 func (r *lockedSource) Int63() (n int64) {
        r.lk.Lock()
-       n = r.src.Int63()
+       n = r.source().Int63()
        r.lk.Unlock()
        return
 }
 
 func (r *lockedSource) Uint64() (n uint64) {
        r.lk.Lock()
-       n = r.src.Uint64()
+       n = r.source().Uint64()
        r.lk.Unlock()
        return
 }
 
 func (r *lockedSource) Seed(seed int64) {
        r.lk.Lock()
-       r.src.Seed(seed)
+       r.seed(seed)
        r.lk.Unlock()
 }
 
 // seedPos implements Seed for a lockedSource without a race condition.
 func (r *lockedSource) seedPos(seed int64, readPos *int8) {
        r.lk.Lock()
-       r.src.Seed(seed)
+       r.seed(seed)
        *readPos = 0
        r.lk.Unlock()
 }
 
+// seed seeds the underlying source.
+// The caller must have locked r.lk.
+func (r *lockedSource) seed(seed int64) {
+       if r.s == nil {
+               r.s = newSource(seed)
+       } else {
+               r.s.Seed(seed)
+       }
+}
+
 // read implements Read for a lockedSource without a race condition.
 func (r *lockedSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) {
        r.lk.Lock()
-       n, err = read(p, r.src, readVal, readPos)
+       n, err = read(p, r.source(), readVal, readPos)
        r.lk.Unlock()
        return
 }