Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
fever-ch
GitHub Repository: fever-ch/go-google-sites-proxy
Path: blob/master/common/lazycontainer.go
508 views
1
package common
2
3
import (
4
"sync"
5
"sync/atomic"
6
"unsafe"
7
)
8
9
// LazyContainer is a lazy datastructure that allows a single evaluation of a given function
10
type LazyContainer struct {
11
// Get returns the value generated by the function (computes it if needed)
12
Get func() unsafe.Pointer
13
}
14
15
const (
16
empty uint32 = iota
17
gettingReady
18
ready
19
)
20
21
// NewLazyContainer returns a LazyContainer that will contain the result of the given fonction
22
func NewLazyContainer(f func() unsafe.Pointer) *LazyContainer {
23
lc := LazyContainer{}
24
var content unsafe.Pointer
25
var mtx sync.Mutex
26
27
status := empty
28
29
prepare := func() unsafe.Pointer {
30
mtx.Lock()
31
value := f()
32
atomic.StorePointer(&content, value)
33
34
// next getters doesn't need to look at any lock
35
defer atomic.StoreUint32(&status, ready)
36
defer mtx.Unlock()
37
return value
38
}
39
40
lc.Get = func() unsafe.Pointer {
41
if atomic.LoadUint32(&status) != ready {
42
if atomic.CompareAndSwapUint32(&status, empty, gettingReady) {
43
return prepare()
44
}
45
// IT IS GETTING READY
46
// tries to acquire the lock and release it
47
for atomic.LoadUint32(&status) != ready {
48
mtx.Lock()
49
mtx.Unlock()
50
}
51
}
52
53
return atomic.LoadPointer(&content)
54
}
55
56
return &lc
57
}
58
59