From c68a85227c5c3dae0b55b83f983015e46bf2a7d1 Mon Sep 17 00:00:00 2001 From: Julien Schmidt Date: Mon, 23 Sep 2019 00:21:18 +0200 Subject: [PATCH] Add int wrapper --- atom.go | 37 +++++++++++++++++++++++++++++ atom_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/atom.go b/atom.go index 01d46f1..ee8cdc0 100644 --- a/atom.go +++ b/atom.go @@ -219,6 +219,43 @@ func (f *Float64) Value() (value float64) { return math.Float64frombits(atomic.LoadUint64(&f.value)) } +// Int is a wrapper for atomically accessed int values. +type Int struct { + _noCopy noCopy + value uintptr +} + +// Add atomically adds delta to the current value and returns the new value. +func (i *Int) Add(delta int) (new int) { + return int(atomic.AddUintptr(&i.value, uintptr(delta))) +} + +// CompareAndSwap atomically sets the new value only if the current value +// matches the given old value and returns whether the new value was set. +func (i *Int) CompareAndSwap(old, new int) (swapped bool) { + return atomic.CompareAndSwapUintptr(&i.value, uintptr(old), uintptr(new)) +} + +// Set sets the new value regardless of the previous value. +func (i *Int) Set(value int) { + atomic.StoreUintptr(&i.value, uintptr(value)) +} + +// Sub atomically subtracts delta to the current value and returns the new value. +func (i *Int) Sub(delta int) (new int) { + return i.Add(-delta) +} + +// Swap atomically sets the new value and returns the previous value. +func (i *Int) Swap(new int) (old int) { + return int(atomic.SwapUintptr(&i.value, uintptr(new))) +} + +// Value returns the current value. +func (i *Int) Value() (value int) { + return int(atomic.LoadUintptr(&i.value)) +} + // Int32 is a wrapper for atomically accessed int32 values. type Int32 struct { _noCopy noCopy diff --git a/atom_test.go b/atom_test.go index cfdd20e..46e87b9 100644 --- a/atom_test.go +++ b/atom_test.go @@ -7,8 +7,11 @@ import ( ) const ( - minUint = 0 maxUint = ^uint(0) + minUint = 0 + + maxInt = int(maxUint >> 1) + minInt = -maxInt - 1 ) func TestBool(t *testing.T) { @@ -207,6 +210,68 @@ func TestFloat64(t *testing.T) { } } +func TestInt(t *testing.T) { + var i Int + if i.Value() != 0 { + t.Fatal("Expected initial value to be 0") + } + + var v1 int = 1337 + i.Set(v1) + if v := i.Value(); v != v1 { + t.Fatal("Value unchanged") + } + + if v := i.Sub(v1); v != 0 { + t.Fatal("New value does not match:", v) + } + if v := i.Add(v1); v != v1 { + t.Fatal("New value does not match:", v) + } + + var v2 int = 987654321 + if i.CompareAndSwap(v2, v2) { + t.Fatal("CompareAndSwap reported swap when the old value did not match") + } + if v := i.Value(); v != v1 { + t.Fatal("Value changed") + } + + if !i.CompareAndSwap(v1, v2) { + t.Fatal("CompareAndSwap did not report a swap") + } + if v := i.Value(); v != v2 { + t.Fatal("Value unchanged") + } + + if v := i.Swap(v1); v != v2 { + t.Fatal("Old value does not match:", v) + } + if v := i.Value(); v != v1 { + t.Fatal("Value unchanged") + } + + // test underflow behavior + v3 := int(minInt) + i.Set(v3) + if v := i.Value(); v != v3 { + t.Fatal("Value unchanged") + } + if v := i.Sub(1); v != (v3 - 1) { + t.Fatal("New value does not match:", v) + } + + // test overflow behavior + v4 := int(maxInt) + i.Set(v4) + if v := i.Value(); v != v4 { + t.Fatal("Value unchanged") + } + if v := i.Add(1); v != (v4 + 1) { + t.Fatal("New value does not match:", v) + } +} + func TestInt32(t *testing.T) { var i Int32 if i.Value() != 0 {