github.com/mitranim/gg@v0.1.17/sync.go (about) 1 package gg 2 3 import ( 4 "sync" 5 "sync/atomic" 6 ) 7 8 /* 9 Shortcut for mutexes. Usage: 10 11 defer Lock(someLock).Unlock() 12 */ 13 func Lock[A sync.Locker](val A) A { 14 val.Lock() 15 return val 16 } 17 18 /* 19 Shortcut for dereferencing a pointer under a lock. Uses `PtrGet`, returning the 20 zero value of the given type if the pointer is nil. 21 */ 22 func LockGet[Lock sync.Locker, Val any](lock Lock, ptr *Val) (_ Val) { 23 if ptr == nil { 24 return 25 } 26 defer Lock(lock).Unlock() 27 return *ptr 28 } 29 30 // Shortcut for writing to a pointer under a lock. 31 func LockSet[Lock sync.Locker, Val any](lock Lock, ptr *Val, val Val) { 32 if ptr == nil { 33 return 34 } 35 defer Lock(lock).Unlock() 36 *ptr = val 37 } 38 39 /* 40 Typed version of `atomic.Value`. Currently implemented as a typedef of 41 `atomic.Value` where the value is internally stored as `any`. Converting 42 non-interface values to `any` may automatically create a copy on the heap. 43 Values other than booleans and machine numbers should be stored by pointer to 44 minimize copying. This may change in the future. 45 */ 46 type Atom[A any] atomic.Value 47 48 /* 49 Like `.Load` but returns true if anything was previously stored, and false if 50 nothing was previously stored. 51 */ 52 func (self *Atom[A]) Loaded() (A, bool) { 53 val := (*atomic.Value)(self).Load() 54 return AnyAs[A](val), val != nil 55 } 56 57 // Typed version of `atomic.Value.Load`. 58 func (self *Atom[A]) Load() A { 59 return AnyAs[A]((*atomic.Value)(self).Load()) 60 } 61 62 // Typed version of `atomic.Value.Store`. 63 func (self *Atom[A]) Store(val A) { 64 (*atomic.Value)(self).Store(val) 65 } 66 67 // Typed version of `atomic.Value.Swap`. 68 func (self *Atom[A]) Swap(val A) A { 69 return AnyAs[A]((*atomic.Value)(self).Swap(val)) 70 } 71 72 // Typed version of `atomic.Value.CompareAndSwap`. 73 func (self *Atom[A]) CompareAndSwap(prev, next A) bool { 74 return (*atomic.Value)(self).CompareAndSwap(prev, next) 75 } 76 77 /* 78 Typed version of `sync.Map`. Currently implemented as a typedef of `sync.Map` 79 where both keys and valus are internally stored as `any`. Converting 80 non-interface values to `any` may automatically create a copy on the heap. 81 Values other than booleans and machine numbers should be stored by pointer to 82 minimize copying. This may change in the future. 83 */ 84 type SyncMap[Key comparable, Val any] sync.Map 85 86 // Typed version of `sync.Map.Load`. 87 func (self *SyncMap[Key, Val]) Load(key Key) (Val, bool) { 88 iface, ok := (*sync.Map)(self).Load(key) 89 return AnyAs[Val](iface), ok 90 } 91 92 // Typed version of `sync.Map.LoadOrStore`. 93 func (self *SyncMap[Key, Val]) LoadOrStore(key Key, val Val) (Val, bool) { 94 iface, ok := (*sync.Map)(self).LoadOrStore(key, val) 95 return AnyAs[Val](iface), ok 96 } 97 98 // Typed version of `sync.Map.LoadAndDelete`. 99 func (self *SyncMap[Key, Val]) LoadAndDelete(key Key) (Val, bool) { 100 iface, ok := (*sync.Map)(self).LoadAndDelete(key) 101 return AnyAs[Val](iface), ok 102 } 103 104 // Typed version of `sync.Map.Store`. 105 func (self *SyncMap[Key, Val]) Store(key Key, val Val) Val { 106 (*sync.Map)(self).Store(key, val) 107 return val 108 } 109 110 // Typed version of `sync.Map.Delete`. 111 func (self *SyncMap[Key, Val]) Delete(key Key) { 112 (*sync.Map)(self).Delete(key) 113 } 114 115 // Typed version of `sync.Map.Range`. 116 func (self *SyncMap[Key, Val]) Range(fun func(Key, Val) bool) { 117 if fun == nil { 118 return 119 } 120 (*sync.Map)(self).Range(func(key, val any) bool { 121 return fun(key.(Key), val.(Val)) 122 }) 123 } 124 125 // Alias of `chan` with additional convenience methods. 126 type Chan[A any] chan A 127 128 // Closes the channel unless it's nil. 129 func (self Chan[_]) Close() { 130 if self != nil { 131 close(self) 132 } 133 } 134 135 // Same as global `ChanInit`. 136 func (self *Chan[A]) Init() Chan[A] { return ChanInit(self) } 137 138 /* 139 Idempotently initializes the channel. If the pointer is non-nil and the channel 140 is nil, creates a new unbuffered channel and assigns it to the pointer. Returns 141 the resulting channel. 142 */ 143 func ChanInit[Tar ~chan Val, Val any](ptr *Tar) Tar { 144 if ptr == nil { 145 return nil 146 } 147 if *ptr == nil { 148 *ptr = make(Tar) 149 } 150 return *ptr 151 } 152 153 // Same as global `ChanInitCap`. 154 func (self *Chan[A]) InitCap(cap int) Chan[A] { return ChanInitCap(self, cap) } 155 156 /* 157 Idempotently initializes the channel. If the pointer is non-nil and the channel 158 is nil, creates a new buffered channel with the given capacity and assigns it 159 to the pointer. Returns the resulting channel. 160 */ 161 func ChanInitCap[Tar ~chan Val, Val any](ptr *Tar, cap int) Tar { 162 if ptr == nil { 163 return nil 164 } 165 if *ptr == nil { 166 *ptr = make(Tar, cap) 167 } 168 return *ptr 169 } 170 171 // Same as global `SendOpt`. 172 func (self Chan[A]) SendOpt(val A) { SendOpt(self, val) } 173 174 // Shortcut for sending a value over a channel in a non-blocking fashion. 175 func SendOpt[Tar ~chan Val, Val any](tar Tar, val Val) { 176 select { 177 case tar <- val: 178 default: 179 } 180 } 181 182 // Same as global `SendZeroOpt`. 183 func (self Chan[A]) SendZeroOpt() { SendZeroOpt(self) } 184 185 // Shortcut for sending a zero value over a channel in a non-blocking fashion. 186 func SendZeroOpt[Tar ~chan Val, Val any](tar Tar) { 187 select { 188 case tar <- Zero[Val](): 189 default: 190 } 191 }