mirror of https://github.com/tevino/abool.git
Merge pull request #3 from barryz/add_flip_method
Add Toggle method to invert the value
This commit is contained in:
commit
d91eb651d5
31
README.md
31
README.md
|
@ -18,6 +18,7 @@ cond.IsSet() // Returns true
|
||||||
cond.UnSet() // Set to false
|
cond.UnSet() // Set to false
|
||||||
cond.SetTo(true) // Set to whatever you want
|
cond.SetTo(true) // Set to whatever you want
|
||||||
cond.SetToIf(false, true) // Set to true if it is false, returns false(not set)
|
cond.SetToIf(false, true) // Set to true if it is false, returns false(not set)
|
||||||
|
cond.Toggle() *AtomicBool // Negates boolean atomically and returns a new AtomicBool object which holds previous boolean value.
|
||||||
|
|
||||||
|
|
||||||
// embedding
|
// embedding
|
||||||
|
@ -26,24 +27,32 @@ type Foo struct {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Benchmark:
|
## Benchmark
|
||||||
|
|
||||||
- Go 1.6.2
|
- Go 1.11.5
|
||||||
- OS X 10.11.4
|
- OS X 10.14.5
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Read
|
# Read
|
||||||
BenchmarkMutexRead-4 100000000 21.0 ns/op
|
BenchmarkMutexRead-4 100000000 14.7 ns/op
|
||||||
BenchmarkAtomicValueRead-4 200000000 6.30 ns/op
|
BenchmarkAtomicValueRead-4 2000000000 0.45 ns/op
|
||||||
BenchmarkAtomicBoolRead-4 300000000 4.21 ns/op # <--- This package
|
BenchmarkAtomicBoolRead-4 2000000000 0.35 ns/op # <--- This package
|
||||||
|
|
||||||
# Write
|
# Write
|
||||||
BenchmarkMutexWrite-4 100000000 21.6 ns/op
|
BenchmarkMutexWrite-4 100000000 14.5 ns/op
|
||||||
BenchmarkAtomicValueWrite-4 30000000 43.4 ns/op
|
BenchmarkAtomicValueWrite-4 100000000 10.5 ns/op
|
||||||
BenchmarkAtomicBoolWrite-4 200000000 9.87 ns/op # <--- This package
|
BenchmarkAtomicBoolWrite-4 300000000 5.21 ns/op # <--- This package
|
||||||
|
|
||||||
# CAS
|
# CAS
|
||||||
BenchmarkMutexCAS-4 30000000 44.9 ns/op
|
BenchmarkMutexCAS-4 50000000 31.3 ns/op
|
||||||
BenchmarkAtomicBoolCAS-4 100000000 11.7 ns/op # <--- This package
|
BenchmarkAtomicBoolCAS-4 200000000 7.18 ns/op # <--- This package
|
||||||
|
|
||||||
|
# Toggle
|
||||||
|
BenchmarkMutexToggle-4 50000000 32.6 ns/op
|
||||||
|
BenchmarkAtomicBoolToggle-4 300000000 5.21 ns/op # <--- This package
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Thanks to these Contributors
|
||||||
|
|
||||||
|
- [@barryz](https://github.com/barryz)
|
||||||
|
- Added the `Toggle` method
|
||||||
|
|
9
bool.go
9
bool.go
|
@ -37,10 +37,10 @@ func (ab *AtomicBool) UnSet() {
|
||||||
|
|
||||||
// IsSet returns whether the Boolean is true
|
// IsSet returns whether the Boolean is true
|
||||||
func (ab *AtomicBool) IsSet() bool {
|
func (ab *AtomicBool) IsSet() bool {
|
||||||
return atomic.LoadInt32((*int32)(ab)) == 1
|
return atomic.LoadInt32((*int32)(ab))&1 == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTo sets the boolean with given Boolean
|
// SetTo sets the boolean with given Boolean.
|
||||||
func (ab *AtomicBool) SetTo(yes bool) {
|
func (ab *AtomicBool) SetTo(yes bool) {
|
||||||
if yes {
|
if yes {
|
||||||
atomic.StoreInt32((*int32)(ab), 1)
|
atomic.StoreInt32((*int32)(ab), 1)
|
||||||
|
@ -49,6 +49,11 @@ func (ab *AtomicBool) SetTo(yes bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle inverts the boolean then returns the value before inverting.
|
||||||
|
func (ab *AtomicBool) Toggle() bool {
|
||||||
|
return atomic.AddInt32((*int32)(ab), 1)&1 == 0
|
||||||
|
}
|
||||||
|
|
||||||
// SetToIf sets the Boolean to new only if the Boolean matches the old
|
// SetToIf sets the Boolean to new only if the Boolean matches the old
|
||||||
// Returns whether the set was done
|
// Returns whether the set was done
|
||||||
func (ab *AtomicBool) SetToIf(old, new bool) (set bool) {
|
func (ab *AtomicBool) SetToIf(old, new bool) (set bool) {
|
||||||
|
|
105
bool_test.go
105
bool_test.go
|
@ -1,12 +1,15 @@
|
||||||
package abool
|
package abool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBool(t *testing.T) {
|
func TestBool(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
v := NewBool(true)
|
v := NewBool(true)
|
||||||
if !v.IsSet() {
|
if !v.IsSet() {
|
||||||
t.Fatal("NewValue(true) failed")
|
t.Fatal("NewValue(true) failed")
|
||||||
|
@ -49,12 +52,80 @@ func TestBool(t *testing.T) {
|
||||||
if set := v.SetToIf(false, true); !set || !v.IsSet() {
|
if set := v.SetToIf(false, true); !set || !v.IsSet() {
|
||||||
t.Fatal("AtomicBool.SetTo(false, true) failed")
|
t.Fatal("AtomicBool.SetTo(false, true) failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v = New()
|
||||||
|
if v.IsSet() {
|
||||||
|
t.Fatal("Empty value of AtomicBool should be false")
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = v.Toggle()
|
||||||
|
if !v.IsSet() {
|
||||||
|
t.Fatal("AtomicBool.Toggle() to true failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
prev := v.Toggle()
|
||||||
|
if v.IsSet() == prev {
|
||||||
|
t.Fatal("AtomicBool.Toggle() to false failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToogleMultipleTimes(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
v := New()
|
||||||
|
pre := !v.IsSet()
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
v.SetTo(false)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
pre = v.Toggle()
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := i%2 != 0
|
||||||
|
if v.IsSet() != expected {
|
||||||
|
t.Fatalf("AtomicBool.Toogle() doesn't work after %d calls, expected: %v, got %v", i, expected, v.IsSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
if pre == v.IsSet() {
|
||||||
|
t.Fatalf("AtomicBool.Toogle() returned wrong value at the %dth calls, expected: %v, got %v", i, !v.IsSet(), pre)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToogleAfterOverflow(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var value int32 = math.MaxInt32
|
||||||
|
v := (*AtomicBool)(&value)
|
||||||
|
|
||||||
|
valueBeforeToggle := *(*int32)(v)
|
||||||
|
|
||||||
|
// test first toggle after overflow
|
||||||
|
v.Toggle()
|
||||||
|
expected := math.MaxInt32%2 == 0
|
||||||
|
if v.IsSet() != expected {
|
||||||
|
t.Fatalf("AtomicBool.Toogle() doesn't work after overflow, expected: %v, got %v", expected, v.IsSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure overflow happened
|
||||||
|
var valueAfterToggle int32 = *(*int32)(v)
|
||||||
|
if valueAfterToggle >= valueBeforeToggle {
|
||||||
|
t.Fatalf("Overflow does not happen as expected, before %d, after: %d", valueBeforeToggle, valueAfterToggle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test second toggle after overflow
|
||||||
|
v.Toggle()
|
||||||
|
expected = !expected
|
||||||
|
if v.IsSet() != expected {
|
||||||
|
t.Fatalf("AtomicBool.Toogle() doesn't work after the second call after overflow, expected: %v, got %v", expected, v.IsSet())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRace(t *testing.T) {
|
func TestRace(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
repeat := 10000
|
repeat := 10000
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(repeat * 3)
|
wg.Add(repeat * 4)
|
||||||
v := New()
|
v := New()
|
||||||
|
|
||||||
// Writer
|
// Writer
|
||||||
|
@ -80,6 +151,15 @@ func TestRace(t *testing.T) {
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Reader And Writer
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < repeat; i++ {
|
||||||
|
v.Toggle()
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +169,7 @@ func ExampleAtomicBool() {
|
||||||
cond.IsSet() // returns true
|
cond.IsSet() // returns true
|
||||||
cond.UnSet() // set to false
|
cond.UnSet() // set to false
|
||||||
cond.SetTo(true) // set to whatever you want
|
cond.SetTo(true) // set to whatever you want
|
||||||
|
cond.Toggle() // toggles the boolean value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Benchmark Read
|
// Benchmark Read
|
||||||
|
@ -174,3 +255,25 @@ func BenchmarkAtomicBoolCAS(b *testing.B) {
|
||||||
v.SetToIf(false, true)
|
v.SetToIf(false, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Benchmark toggle boolean value
|
||||||
|
|
||||||
|
func BenchmarkMutexToggle(b *testing.B) {
|
||||||
|
var m sync.RWMutex
|
||||||
|
var v bool
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
m.Lock()
|
||||||
|
v = !v
|
||||||
|
m.Unlock()
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAtomicBoolToggle(b *testing.B) {
|
||||||
|
v := New()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.Toggle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue