diff --git a/README.md b/README.md index 392bf8c..c1e199a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,29 @@ -# abool -Atomic boolean library for Golang, optimized for performance yet simple to use. +# ABool +:bulb: Atomic boolean library for Golang, optimized for performance yet simple to use. + +## Benchmark: + +- Golang 1.6.2 +- OS X 10.11.4 + +``` +# Read +BenchmarkMutexRead-4 100000000 21.1 ns/op +BenchmarkAtomicValueRead-4 200000000 6.33 ns/op +BenchmarkAtomicBoolRead-4 300000000 4.28 ns/op + +# Write +BenchmarkMutexWrite-4 100000000 21.7 ns/op +BenchmarkAtomicValueWrite-4 30000000 47.8 ns/op +BenchmarkAtomicBoolWrite-4 200000000 9.83 ns/op +``` + +## Usage + +``` +var v AtomicBool +v.Set() // set to true +v.IsSet() // returns true +v.UnSet() // set to false +v.SetTo(true) // set with gieven boolean +``` diff --git a/bool.go b/bool.go new file mode 100644 index 0000000..061f346 --- /dev/null +++ b/bool.go @@ -0,0 +1,37 @@ +package abool + +import "sync/atomic" + +// New creates a pointer to an AtomicBool +func New() *AtomicBool { + return new(AtomicBool) +} + +// AtomicBool is a atomic boolean +// Note: When embedding into a struct, one should always use +// *AtomicBool to avoid copy +type AtomicBool int32 + +// SetTo sets the boolean with given bool +func (ab *AtomicBool) SetTo(yes bool) { + if yes { + atomic.StoreInt32((*int32)(ab), 1) + } else { + atomic.StoreInt32((*int32)(ab), 0) + } +} + +// Set sets the bool to true +func (ab *AtomicBool) Set() { + atomic.StoreInt32((*int32)(ab), 1) +} + +// UnSet sets the bool to false +func (ab *AtomicBool) UnSet() { + atomic.StoreInt32((*int32)(ab), 0) +} + +// IsSet returns whether the bool is true +func (ab *AtomicBool) IsSet() bool { + return atomic.LoadInt32((*int32)(ab)) == 1 +} diff --git a/bool_test.go b/bool_test.go new file mode 100644 index 0000000..89c3209 --- /dev/null +++ b/bool_test.go @@ -0,0 +1,94 @@ +package abool + +import ( + "sync" + "sync/atomic" + "testing" +) + +func TestBool(t *testing.T) { + v := New() + if v.IsSet() { + t.Fatal("Empty value of AtomicBool should be false") + } + + v.Set() + if !v.IsSet() { + t.Fatal("AtomicBool.Set() failed") + } + + v.UnSet() + if v.IsSet() { + t.Fatal("AtomicBool.UnSet() failed") + } + + v.SetTo(true) + if !v.IsSet() { + t.Fatal("AtomicBool.SetTo(true) failed") + } + + v.SetTo(false) + if v.IsSet() { + t.Fatal("AtomicBool.SetTo(false) failed") + } +} + +// Benchmark Read + +func BenchmarkMutexRead(b *testing.B) { + var m sync.RWMutex + var v bool + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.RLock() + _ = v + m.RUnlock() + } +} + +func BenchmarkAtomicValueRead(b *testing.B) { + var v atomic.Value + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = v.Load() != nil + } +} + +func BenchmarkAtomicBoolRead(b *testing.B) { + v := New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = v.IsSet() + } +} + +// Benchmark Write + +func BenchmarkMutexWrite(b *testing.B) { + var m sync.RWMutex + var v bool + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.RLock() + v = true + m.RUnlock() + } + b.StopTimer() + _ = v +} + +func BenchmarkAtomicValueWrite(b *testing.B) { + var v atomic.Value + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.Store(true) + } +} + +func BenchmarkAtomicBoolWrite(b *testing.B) { + v := New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.Set() + } +}