mirror of https://github.com/golang/go.git
110 lines
2.3 KiB
Go
110 lines
2.3 KiB
Go
// Copyright 2022 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package sync
|
|
|
|
// OnceFunc returns a function that invokes f only once. The returned function
|
|
// may be called concurrently.
|
|
//
|
|
// If f panics, the returned function will panic with the same value on every call.
|
|
func OnceFunc(f func()) func() {
|
|
// Use a struct so that there's a single heap allocation.
|
|
d := struct {
|
|
f func()
|
|
once Once
|
|
valid bool
|
|
p any
|
|
}{
|
|
f: f,
|
|
}
|
|
return func() {
|
|
d.once.Do(func() {
|
|
defer func() {
|
|
d.f = nil // Do not keep f alive after invoking it.
|
|
d.p = recover()
|
|
if !d.valid {
|
|
// Re-panic immediately so on the first
|
|
// call the user gets a complete stack
|
|
// trace into f.
|
|
panic(d.p)
|
|
}
|
|
}()
|
|
d.f()
|
|
d.valid = true // Set only if f does not panic.
|
|
})
|
|
if !d.valid {
|
|
panic(d.p)
|
|
}
|
|
}
|
|
}
|
|
|
|
// OnceValue returns a function that invokes f only once and returns the value
|
|
// returned by f. The returned function may be called concurrently.
|
|
//
|
|
// If f panics, the returned function will panic with the same value on every call.
|
|
func OnceValue[T any](f func() T) func() T {
|
|
// Use a struct so that there's a single heap allocation.
|
|
d := struct {
|
|
f func() T
|
|
once Once
|
|
valid bool
|
|
p any
|
|
result T
|
|
}{
|
|
f: f,
|
|
}
|
|
return func() T {
|
|
d.once.Do(func() {
|
|
defer func() {
|
|
d.f = nil
|
|
d.p = recover()
|
|
if !d.valid {
|
|
panic(d.p)
|
|
}
|
|
}()
|
|
d.result = d.f()
|
|
d.valid = true
|
|
})
|
|
if !d.valid {
|
|
panic(d.p)
|
|
}
|
|
return d.result
|
|
}
|
|
}
|
|
|
|
// OnceValues returns a function that invokes f only once and returns the values
|
|
// returned by f. The returned function may be called concurrently.
|
|
//
|
|
// If f panics, the returned function will panic with the same value on every call.
|
|
func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
|
|
// Use a struct so that there's a single heap allocation.
|
|
d := struct {
|
|
f func() (T1, T2)
|
|
once Once
|
|
valid bool
|
|
p any
|
|
r1 T1
|
|
r2 T2
|
|
}{
|
|
f: f,
|
|
}
|
|
return func() (T1, T2) {
|
|
d.once.Do(func() {
|
|
defer func() {
|
|
d.f = nil
|
|
d.p = recover()
|
|
if !d.valid {
|
|
panic(d.p)
|
|
}
|
|
}()
|
|
d.r1, d.r2 = d.f()
|
|
d.valid = true
|
|
})
|
|
if !d.valid {
|
|
panic(d.p)
|
|
}
|
|
return d.r1, d.r2
|
|
}
|
|
}
|