github.com/mitranim/gg@v0.1.17/lazy_initer.go (about) 1 package gg 2 3 import "sync" 4 5 /* 6 Shortcut for type inference. The following is equivalent: 7 8 NewLazyIniter[Val]() 9 new(LazyIniter[Val, Ptr]) 10 */ 11 func NewLazyIniter[Val any, Ptr IniterPtr[Val]]() *LazyIniter[Val, Ptr] { 12 return new(LazyIniter[Val, Ptr]) 13 } 14 15 /* 16 Encapsulates a lazily-initializable value. The first call to `.Get` or `.Ptr` 17 initializes the underlying value by calling its `.Init` method. Initialization 18 is performed exactly once. Access is synchronized. All methods are 19 concurrency-safe. Designed to be embeddable. A zero value is ready to use. When 20 using this as a struct field, you don't need to explicitly initialize the 21 field. Contains a mutex and must not be copied. 22 */ 23 type LazyIniter[Val any, Ptr IniterPtr[Val]] struct { 24 val Opt[Val] 25 lock sync.RWMutex 26 } 27 28 // Returns the underlying value, lazily initializing it on the first call. 29 func (self *LazyIniter[Val, _]) Get() Val { return *self.Ptr() } 30 31 /* 32 Returns a pointer to the underlying value, lazily initializing it on the first 33 call. 34 */ 35 func (self *LazyIniter[_, Ptr]) Ptr() Ptr { 36 if self.inited() { 37 return self.ptr() 38 } 39 return self.init() 40 } 41 42 func (self *LazyIniter[_, Ptr]) ptr() Ptr { return &self.val.Val } 43 44 func (self *LazyIniter[_, _]) inited() bool { 45 self.lock.RLock() 46 defer self.lock.RUnlock() 47 return self.val.IsNotNull() 48 } 49 50 func (self *LazyIniter[_, Ptr]) init() Ptr { 51 self.lock.Lock() 52 defer self.lock.Unlock() 53 if self.val.IsNotNull() { 54 return self.ptr() 55 } 56 57 Ptr(&self.val.Val).Init() 58 self.val.Ok = true 59 return self.ptr() 60 }