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. 23package atomic 24 25import ( 26 "math" 27 "sync/atomic" 28 "time" 29) 30 31// Int32 is an atomic wrapper around an int32. 32type Int32 struct{ v int32 } 33 34// NewInt32 creates an Int32. 35func NewInt32(i int32) *Int32 { 36 return &Int32{i} 37} 38 39// Load atomically loads the wrapped value. 40func (i *Int32) Load() int32 { 41 return atomic.LoadInt32(&i.v) 42} 43 44// Add atomically adds to the wrapped int32 and returns the new value. 45func (i *Int32) Add(n int32) int32 { 46 return atomic.AddInt32(&i.v, n) 47} 48 49// Sub atomically subtracts from the wrapped int32 and returns the new value. 50func (i *Int32) Sub(n int32) int32 { 51 return atomic.AddInt32(&i.v, -n) 52} 53 54// Inc atomically increments the wrapped int32 and returns the new value. 55func (i *Int32) Inc() int32 { 56 return i.Add(1) 57} 58 59// Dec atomically decrements the wrapped int32 and returns the new value. 60func (i *Int32) Dec() int32 { 61 return i.Sub(1) 62} 63 64// CAS is an atomic compare-and-swap. 65func (i *Int32) CAS(old, new int32) bool { 66 return atomic.CompareAndSwapInt32(&i.v, old, new) 67} 68 69// Store atomically stores the passed value. 70func (i *Int32) Store(n int32) { 71 atomic.StoreInt32(&i.v, n) 72} 73 74// Swap atomically swaps the wrapped int32 and returns the old value. 75func (i *Int32) Swap(n int32) int32 { 76 return atomic.SwapInt32(&i.v, n) 77} 78 79// Int64 is an atomic wrapper around an int64. 80type Int64 struct{ v int64 } 81 82// NewInt64 creates an Int64. 83func NewInt64(i int64) *Int64 { 84 return &Int64{i} 85} 86 87// Load atomically loads the wrapped value. 88func (i *Int64) Load() int64 { 89 return atomic.LoadInt64(&i.v) 90} 91 92// Add atomically adds to the wrapped int64 and returns the new value. 93func (i *Int64) Add(n int64) int64 { 94 return atomic.AddInt64(&i.v, n) 95} 96 97// Sub atomically subtracts from the wrapped int64 and returns the new value. 98func (i *Int64) Sub(n int64) int64 { 99 return atomic.AddInt64(&i.v, -n) 100} 101 102// Inc atomically increments the wrapped int64 and returns the new value. 103func (i *Int64) Inc() int64 { 104 return i.Add(1) 105} 106 107// Dec atomically decrements the wrapped int64 and returns the new value. 108func (i *Int64) Dec() int64 { 109 return i.Sub(1) 110} 111 112// CAS is an atomic compare-and-swap. 113func (i *Int64) CAS(old, new int64) bool { 114 return atomic.CompareAndSwapInt64(&i.v, old, new) 115} 116 117// Store atomically stores the passed value. 118func (i *Int64) Store(n int64) { 119 atomic.StoreInt64(&i.v, n) 120} 121 122// Swap atomically swaps the wrapped int64 and returns the old value. 123func (i *Int64) Swap(n int64) int64 { 124 return atomic.SwapInt64(&i.v, n) 125} 126 127// Uint32 is an atomic wrapper around an uint32. 128type Uint32 struct{ v uint32 } 129 130// NewUint32 creates a Uint32. 131func NewUint32(i uint32) *Uint32 { 132 return &Uint32{i} 133} 134 135// Load atomically loads the wrapped value. 136func (i *Uint32) Load() uint32 { 137 return atomic.LoadUint32(&i.v) 138} 139 140// Add atomically adds to the wrapped uint32 and returns the new value. 141func (i *Uint32) Add(n uint32) uint32 { 142 return atomic.AddUint32(&i.v, n) 143} 144 145// Sub atomically subtracts from the wrapped uint32 and returns the new value. 146func (i *Uint32) Sub(n uint32) uint32 { 147 return atomic.AddUint32(&i.v, ^(n - 1)) 148} 149 150// Inc atomically increments the wrapped uint32 and returns the new value. 151func (i *Uint32) Inc() uint32 { 152 return i.Add(1) 153} 154 155// Dec atomically decrements the wrapped int32 and returns the new value. 156func (i *Uint32) Dec() uint32 { 157 return i.Sub(1) 158} 159 160// CAS is an atomic compare-and-swap. 161func (i *Uint32) CAS(old, new uint32) bool { 162 return atomic.CompareAndSwapUint32(&i.v, old, new) 163} 164 165// Store atomically stores the passed value. 166func (i *Uint32) Store(n uint32) { 167 atomic.StoreUint32(&i.v, n) 168} 169 170// Swap atomically swaps the wrapped uint32 and returns the old value. 171func (i *Uint32) Swap(n uint32) uint32 { 172 return atomic.SwapUint32(&i.v, n) 173} 174 175// Uint64 is an atomic wrapper around a uint64. 176type Uint64 struct{ v uint64 } 177 178// NewUint64 creates a Uint64. 179func NewUint64(i uint64) *Uint64 { 180 return &Uint64{i} 181} 182 183// Load atomically loads the wrapped value. 184func (i *Uint64) Load() uint64 { 185 return atomic.LoadUint64(&i.v) 186} 187 188// Add atomically adds to the wrapped uint64 and returns the new value. 189func (i *Uint64) Add(n uint64) uint64 { 190 return atomic.AddUint64(&i.v, n) 191} 192 193// Sub atomically subtracts from the wrapped uint64 and returns the new value. 194func (i *Uint64) Sub(n uint64) uint64 { 195 return atomic.AddUint64(&i.v, ^(n - 1)) 196} 197 198// Inc atomically increments the wrapped uint64 and returns the new value. 199func (i *Uint64) Inc() uint64 { 200 return i.Add(1) 201} 202 203// Dec atomically decrements the wrapped uint64 and returns the new value. 204func (i *Uint64) Dec() uint64 { 205 return i.Sub(1) 206} 207 208// CAS is an atomic compare-and-swap. 209func (i *Uint64) CAS(old, new uint64) bool { 210 return atomic.CompareAndSwapUint64(&i.v, old, new) 211} 212 213// Store atomically stores the passed value. 214func (i *Uint64) Store(n uint64) { 215 atomic.StoreUint64(&i.v, n) 216} 217 218// Swap atomically swaps the wrapped uint64 and returns the old value. 219func (i *Uint64) Swap(n uint64) uint64 { 220 return atomic.SwapUint64(&i.v, n) 221} 222 223// Bool is an atomic Boolean. 224type Bool struct{ v uint32 } 225 226// NewBool creates a Bool. 227func NewBool(initial bool) *Bool { 228 return &Bool{boolToInt(initial)} 229} 230 231// Load atomically loads the Boolean. 232func (b *Bool) Load() bool { 233 return truthy(atomic.LoadUint32(&b.v)) 234} 235 236// CAS is an atomic compare-and-swap. 237func (b *Bool) CAS(old, new bool) bool { 238 return atomic.CompareAndSwapUint32(&b.v, boolToInt(old), boolToInt(new)) 239} 240 241// Store atomically stores the passed value. 242func (b *Bool) Store(new bool) { 243 atomic.StoreUint32(&b.v, boolToInt(new)) 244} 245 246// Swap sets the given value and returns the previous value. 247func (b *Bool) Swap(new bool) bool { 248 return truthy(atomic.SwapUint32(&b.v, boolToInt(new))) 249} 250 251// Toggle atomically negates the Boolean and returns the previous value. 252func (b *Bool) Toggle() bool { 253 return truthy(atomic.AddUint32(&b.v, 1) - 1) 254} 255 256func truthy(n uint32) bool { 257 return n&1 == 1 258} 259 260func boolToInt(b bool) uint32 { 261 if b { 262 return 1 263 } 264 return 0 265} 266 267// Float64 is an atomic wrapper around float64. 268type Float64 struct { 269 v uint64 270} 271 272// NewFloat64 creates a Float64. 273func NewFloat64(f float64) *Float64 { 274 return &Float64{math.Float64bits(f)} 275} 276 277// Load atomically loads the wrapped value. 278func (f *Float64) Load() float64 { 279 return math.Float64frombits(atomic.LoadUint64(&f.v)) 280} 281 282// Store atomically stores the passed value. 283func (f *Float64) Store(s float64) { 284 atomic.StoreUint64(&f.v, math.Float64bits(s)) 285} 286 287// Add atomically adds to the wrapped float64 and returns the new value. 288func (f *Float64) Add(s float64) float64 { 289 for { 290 old := f.Load() 291 new := old + s 292 if f.CAS(old, new) { 293 return new 294 } 295 } 296} 297 298// Sub atomically subtracts from the wrapped float64 and returns the new value. 299func (f *Float64) Sub(s float64) float64 { 300 return f.Add(-s) 301} 302 303// CAS is an atomic compare-and-swap. 304func (f *Float64) CAS(old, new float64) bool { 305 return atomic.CompareAndSwapUint64(&f.v, math.Float64bits(old), math.Float64bits(new)) 306} 307 308// Duration is an atomic wrapper around time.Duration 309// https://godoc.org/time#Duration 310type Duration struct { 311 v Int64 312} 313 314// NewDuration creates a Duration. 315func NewDuration(d time.Duration) *Duration { 316 return &Duration{v: *NewInt64(int64(d))} 317} 318 319// Load atomically loads the wrapped value. 320func (d *Duration) Load() time.Duration { 321 return time.Duration(d.v.Load()) 322} 323 324// Store atomically stores the passed value. 325func (d *Duration) Store(n time.Duration) { 326 d.v.Store(int64(n)) 327} 328 329// Add atomically adds to the wrapped time.Duration and returns the new value. 330func (d *Duration) Add(n time.Duration) time.Duration { 331 return time.Duration(d.v.Add(int64(n))) 332} 333 334// Sub atomically subtracts from the wrapped time.Duration and returns the new value. 335func (d *Duration) Sub(n time.Duration) time.Duration { 336 return time.Duration(d.v.Sub(int64(n))) 337} 338 339// Swap atomically swaps the wrapped time.Duration and returns the old value. 340func (d *Duration) Swap(n time.Duration) time.Duration { 341 return time.Duration(d.v.Swap(int64(n))) 342} 343 344// CAS is an atomic compare-and-swap. 345func (d *Duration) CAS(old, new time.Duration) bool { 346 return d.v.CAS(int64(old), int64(new)) 347} 348 349// Value shadows the type of the same name from sync/atomic 350// https://godoc.org/sync/atomic#Value 351type Value struct{ atomic.Value } 352