A nicer implementation of sync.Once
Doesnt require storing the result of the function in a dedicated global variable with a dedicated getter function
This commit is contained in:
parent
fbaaca1be9
commit
6f4d89045a
35
tools/utils/once.go
Normal file
35
tools/utils/once.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = fmt.Print
|
||||||
|
|
||||||
|
type Once[T any] struct {
|
||||||
|
done uint32
|
||||||
|
mutex sync.Mutex
|
||||||
|
cached_val T
|
||||||
|
|
||||||
|
Run func() T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Once[T]) Get() T {
|
||||||
|
if atomic.LoadUint32(&self.done) == 0 {
|
||||||
|
self.do_slow()
|
||||||
|
}
|
||||||
|
return self.cached_val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Once[T]) do_slow() {
|
||||||
|
self.mutex.Lock()
|
||||||
|
defer self.mutex.Unlock()
|
||||||
|
if atomic.LoadUint32(&self.done) == 0 {
|
||||||
|
defer atomic.StoreUint32(&self.done, 1)
|
||||||
|
self.cached_val = self.Run()
|
||||||
|
}
|
||||||
|
}
|
||||||
24
tools/utils/once_test.go
Normal file
24
tools/utils/once_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = fmt.Print
|
||||||
|
|
||||||
|
func TestOnce(t *testing.T) {
|
||||||
|
num := 0
|
||||||
|
var G = (&Once[string]{Run: func() string {
|
||||||
|
num++
|
||||||
|
return fmt.Sprintf("%d", num)
|
||||||
|
}}).Get
|
||||||
|
G()
|
||||||
|
G()
|
||||||
|
G()
|
||||||
|
if num != 1 {
|
||||||
|
t.Fatalf("num unexpectedly: %d", num)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user