reintroduce Toggle()

This commit is contained in:
Johann Sebastian Schicho 2021-09-05 17:29:37 +02:00
parent 00beeaa184
commit 6ded1b6f08
2 changed files with 32 additions and 31 deletions

View File

@ -58,8 +58,15 @@ func (ab *AtomicBool) SetTo(yes bool) {
} }
// Toggle inverts the Boolean then returns the value before inverting. // Toggle inverts the Boolean then returns the value before inverting.
// Based on: https://github.com/uber-go/atomic/blob/3504dfaa1fa414923b1c8693f45d2f6931daf229/bool_ext.go#L40
func (ab *AtomicBool) Toggle() bool { func (ab *AtomicBool) Toggle() bool {
return atomic.AddInt32((*int32)(&ab.boolean), 1)&1 == 0 var old bool
for {
old = ab.IsSet()
if ab.SetToIf(old, !old) {
return old
}
}
} }
// 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.

View File

@ -2,7 +2,6 @@ package abool
import ( import (
"encoding/json" "encoding/json"
"math"
"sync" "sync"
"sync/atomic" "sync/atomic"
"testing" "testing"
@ -110,35 +109,6 @@ func TestToogleMultipleTimes(t *testing.T) {
} }
} }
func TestToogleAfterOverflow(t *testing.T) {
t.Parallel()
var value int32 = math.MaxInt32
v := &AtomicBool{value}
valueBeforeToggle := v.boolean
// 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 = v.boolean
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) {
repeat := 10000 repeat := 10000
var wg sync.WaitGroup var wg sync.WaitGroup
@ -171,6 +141,22 @@ func TestRace(t *testing.T) {
wg.Wait() wg.Wait()
} }
func TestSetToIfAfterMultipleToggles(t *testing.T) {
v := New() // false
v.Toggle() // true
v.Toggle() // false
v.Toggle() // true
// As v is true, it should now be flipped to false
v.SetToIf(true, false)
expected := false
if v.IsSet() != expected {
t.Fatalf("Toggling the value atleast 3 times, until it's true, `SetToIf(true, false)` should flip v to false, expected: %v, got %v", expected, v.IsSet())
}
}
func TestJSONCompatibleWithBuiltinBool(t *testing.T) { func TestJSONCompatibleWithBuiltinBool(t *testing.T) {
for _, value := range []bool{true, false} { for _, value := range []bool{true, false} {
// Test bool -> bytes -> AtomicBool // Test bool -> bytes -> AtomicBool
@ -248,6 +234,14 @@ func ExampleAtomicBool() {
cond.SetToIf(new, old) // Sets to `new` only if the Boolean matches the `old`, returns whether succeeded cond.SetToIf(new, old) // Sets to `new` only if the Boolean matches the `old`, returns whether succeeded
} }
func BenchmarkAtomicBoolToggle(b *testing.B) {
v := New()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = v.Toggle()
}
}
// Benchmark Read // Benchmark Read
func BenchmarkMutexRead(b *testing.B) { func BenchmarkMutexRead(b *testing.B) {