atom.go (9816B)
1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 // Package atomic provides simple wrappers around numerics to enforce atomic 22 // access. 23 24 package atom 25 26 import ( 27 "math" 28 "sync/atomic" 29 "time" 30 ) 31 32 // Int32 is an atomic wrapper around an int32. 33 type Int32 struct{ v int32 } 34 35 // NewInt32 creates an Int32. 36 func NewInt32(i int32) *Int32 { 37 return &Int32{i} 38 } 39 40 // Load atomically loads the wrapped value. 41 func (i *Int32) Load() int32 { 42 return atomic.LoadInt32(&i.v) 43 } 44 45 // Add atomically adds to the wrapped int32 and returns the new value. 46 func (i *Int32) Add(n int32) int32 { 47 return atomic.AddInt32(&i.v, n) 48 } 49 50 // Sub atomically subtracts from the wrapped int32 and returns the new value. 51 func (i *Int32) Sub(n int32) int32 { 52 return atomic.AddInt32(&i.v, -n) 53 } 54 55 // Inc atomically increments the wrapped int32 and returns the new value. 56 func (i *Int32) Inc() int32 { 57 return i.Add(1) 58 } 59 60 // Dec atomically decrements the wrapped int32 and returns the new value. 61 func (i *Int32) Dec() int32 { 62 return i.Sub(1) 63 } 64 65 // CAS is an atomic compare-and-swap. 66 func (i *Int32) CAS(old, new int32) bool { 67 return atomic.CompareAndSwapInt32(&i.v, old, new) 68 } 69 70 // Store atomically stores the passed value. 71 func (i *Int32) Store(n int32) { 72 atomic.StoreInt32(&i.v, n) 73 } 74 75 // Swap atomically swaps the wrapped int32 and returns the old value. 76 func (i *Int32) Swap(n int32) int32 { 77 return atomic.SwapInt32(&i.v, n) 78 } 79 80 // Int64 is an atomic wrapper around an int64. 81 type Int64 struct{ v int64 } 82 83 // NewInt64 creates an Int64. 84 func NewInt64(i int64) *Int64 { 85 return &Int64{i} 86 } 87 88 // Load atomically loads the wrapped value. 89 func (i *Int64) Load() int64 { 90 return atomic.LoadInt64(&i.v) 91 } 92 93 // Add atomically adds to the wrapped int64 and returns the new value. 94 func (i *Int64) Add(n int64) int64 { 95 return atomic.AddInt64(&i.v, n) 96 } 97 98 // Sub atomically subtracts from the wrapped int64 and returns the new value. 99 func (i *Int64) Sub(n int64) int64 { 100 return atomic.AddInt64(&i.v, -n) 101 } 102 103 // Inc atomically increments the wrapped int64 and returns the new value. 104 func (i *Int64) Inc() int64 { 105 return i.Add(1) 106 } 107 108 // Dec atomically decrements the wrapped int64 and returns the new value. 109 func (i *Int64) Dec() int64 { 110 return i.Sub(1) 111 } 112 113 // CAS is an atomic compare-and-swap. 114 func (i *Int64) CAS(old, new int64) bool { 115 return atomic.CompareAndSwapInt64(&i.v, old, new) 116 } 117 118 // Store atomically stores the passed value. 119 func (i *Int64) Store(n int64) { 120 atomic.StoreInt64(&i.v, n) 121 } 122 123 // Swap atomically swaps the wrapped int64 and returns the old value. 124 func (i *Int64) Swap(n int64) int64 { 125 return atomic.SwapInt64(&i.v, n) 126 } 127 128 // Uint32 is an atomic wrapper around an uint32. 129 type Uint32 struct{ v uint32 } 130 131 // NewUint32 creates a Uint32. 132 func NewUint32(i uint32) *Uint32 { 133 return &Uint32{i} 134 } 135 136 // Load atomically loads the wrapped value. 137 func (i *Uint32) Load() uint32 { 138 return atomic.LoadUint32(&i.v) 139 } 140 141 // Add atomically adds to the wrapped uint32 and returns the new value. 142 func (i *Uint32) Add(n uint32) uint32 { 143 return atomic.AddUint32(&i.v, n) 144 } 145 146 // Sub atomically subtracts from the wrapped uint32 and returns the new value. 147 func (i *Uint32) Sub(n uint32) uint32 { 148 return atomic.AddUint32(&i.v, ^(n - 1)) 149 } 150 151 // Inc atomically increments the wrapped uint32 and returns the new value. 152 func (i *Uint32) Inc() uint32 { 153 return i.Add(1) 154 } 155 156 // Dec atomically decrements the wrapped int32 and returns the new value. 157 func (i *Uint32) Dec() uint32 { 158 return i.Sub(1) 159 } 160 161 // CAS is an atomic compare-and-swap. 162 func (i *Uint32) CAS(old, new uint32) bool { 163 return atomic.CompareAndSwapUint32(&i.v, old, new) 164 } 165 166 // Store atomically stores the passed value. 167 func (i *Uint32) Store(n uint32) { 168 atomic.StoreUint32(&i.v, n) 169 } 170 171 // Swap atomically swaps the wrapped uint32 and returns the old value. 172 func (i *Uint32) Swap(n uint32) uint32 { 173 return atomic.SwapUint32(&i.v, n) 174 } 175 176 // Uint64 is an atomic wrapper around a uint64. 177 type Uint64 struct{ v uint64 } 178 179 // NewUint64 creates a Uint64. 180 func NewUint64(i uint64) *Uint64 { 181 return &Uint64{i} 182 } 183 184 // Load atomically loads the wrapped value. 185 func (i *Uint64) Load() uint64 { 186 return atomic.LoadUint64(&i.v) 187 } 188 189 // Add atomically adds to the wrapped uint64 and returns the new value. 190 func (i *Uint64) Add(n uint64) uint64 { 191 return atomic.AddUint64(&i.v, n) 192 } 193 194 // Sub atomically subtracts from the wrapped uint64 and returns the new value. 195 func (i *Uint64) Sub(n uint64) uint64 { 196 return atomic.AddUint64(&i.v, ^(n - 1)) 197 } 198 199 // Inc atomically increments the wrapped uint64 and returns the new value. 200 func (i *Uint64) Inc() uint64 { 201 return i.Add(1) 202 } 203 204 // Dec atomically decrements the wrapped uint64 and returns the new value. 205 func (i *Uint64) Dec() uint64 { 206 return i.Sub(1) 207 } 208 209 // CAS is an atomic compare-and-swap. 210 func (i *Uint64) CAS(old, new uint64) bool { 211 return atomic.CompareAndSwapUint64(&i.v, old, new) 212 } 213 214 // Store atomically stores the passed value. 215 func (i *Uint64) Store(n uint64) { 216 atomic.StoreUint64(&i.v, n) 217 } 218 219 // Swap atomically swaps the wrapped uint64 and returns the old value. 220 func (i *Uint64) Swap(n uint64) uint64 { 221 return atomic.SwapUint64(&i.v, n) 222 } 223 224 // Bool is an atomic Boolean. 225 type Bool struct{ v uint32 } 226 227 // NewBool creates a Bool. 228 func NewBool(initial bool) *Bool { 229 return &Bool{boolToInt(initial)} 230 } 231 232 // IsFalse return if the current value is true 233 func (b *Bool) IsTrue() bool { 234 return b.Load() 235 } 236 237 // IsFalse return if the current value is false 238 func (b *Bool) IsFalse() bool { 239 return !b.Load() 240 } 241 242 // SetTrue sets current value to true 243 func (b *Bool) SetTrue() { 244 b.Store(true) 245 } 246 247 // SetFalse sets current value to false 248 func (b *Bool) SetFalse() { 249 b.Store(false) 250 } 251 252 // Load atomically loads the Boolean. 253 func (b *Bool) Load() bool { 254 return truthy(atomic.LoadUint32(&b.v)) 255 } 256 257 // CAS is an atomic compare-and-swap. 258 func (b *Bool) CAS(old, new bool) bool { 259 return atomic.CompareAndSwapUint32(&b.v, boolToInt(old), boolToInt(new)) 260 } 261 262 // Store atomically stores the passed value. 263 func (b *Bool) Store(new bool) { 264 atomic.StoreUint32(&b.v, boolToInt(new)) 265 } 266 267 // Swap sets the given value and returns the previous value. 268 func (b *Bool) Swap(new bool) bool { 269 return truthy(atomic.SwapUint32(&b.v, boolToInt(new))) 270 } 271 272 // Toggle atomically negates the Boolean and returns the previous value. 273 func (b *Bool) Toggle() bool { 274 for { 275 old := b.Load() 276 if b.CAS(old, !old) { 277 return old 278 } 279 } 280 } 281 282 func truthy(n uint32) bool { 283 return n == 1 284 } 285 286 func boolToInt(b bool) uint32 { 287 if b { 288 return 1 289 } 290 return 0 291 } 292 293 // Float64 is an atomic wrapper around float64. 294 type Float64 struct { 295 v uint64 296 } 297 298 // NewFloat64 creates a Float64. 299 func NewFloat64(f float64) *Float64 { 300 return &Float64{math.Float64bits(f)} 301 } 302 303 // Load atomically loads the wrapped value. 304 func (f *Float64) Load() float64 { 305 return math.Float64frombits(atomic.LoadUint64(&f.v)) 306 } 307 308 // Store atomically stores the passed value. 309 func (f *Float64) Store(s float64) { 310 atomic.StoreUint64(&f.v, math.Float64bits(s)) 311 } 312 313 // Add atomically adds to the wrapped float64 and returns the new value. 314 func (f *Float64) Add(s float64) float64 { 315 for { 316 old := f.Load() 317 new := old + s 318 if f.CAS(old, new) { 319 return new 320 } 321 } 322 } 323 324 // Sub atomically subtracts from the wrapped float64 and returns the new value. 325 func (f *Float64) Sub(s float64) float64 { 326 return f.Add(-s) 327 } 328 329 // CAS is an atomic compare-and-swap. 330 func (f *Float64) CAS(old, new float64) bool { 331 return atomic.CompareAndSwapUint64(&f.v, math.Float64bits(old), math.Float64bits(new)) 332 } 333 334 // Duration is an atomic wrapper around time.Duration 335 // https://godoc.org/time#Duration 336 type Duration struct { 337 v Int64 338 } 339 340 // NewDuration creates a Duration. 341 func NewDuration(d time.Duration) *Duration { 342 return &Duration{v: *NewInt64(int64(d))} 343 } 344 345 // Load atomically loads the wrapped value. 346 func (d *Duration) Load() time.Duration { 347 return time.Duration(d.v.Load()) 348 } 349 350 // Store atomically stores the passed value. 351 func (d *Duration) Store(n time.Duration) { 352 d.v.Store(int64(n)) 353 } 354 355 // Add atomically adds to the wrapped time.Duration and returns the new value. 356 func (d *Duration) Add(n time.Duration) time.Duration { 357 return time.Duration(d.v.Add(int64(n))) 358 } 359 360 // Sub atomically subtracts from the wrapped time.Duration and returns the new value. 361 func (d *Duration) Sub(n time.Duration) time.Duration { 362 return time.Duration(d.v.Sub(int64(n))) 363 } 364 365 // Swap atomically swaps the wrapped time.Duration and returns the old value. 366 func (d *Duration) Swap(n time.Duration) time.Duration { 367 return time.Duration(d.v.Swap(int64(n))) 368 } 369 370 // CAS is an atomic compare-and-swap. 371 func (d *Duration) CAS(old, new time.Duration) bool { 372 return d.v.CAS(int64(old), int64(new)) 373 } 374 375 // Value shadows the type of the same name from sync/atomic 376 // https://godoc.org/sync/atomic#Value 377 type Value struct{ atomic.Value }