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