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.
// Based on: https://github.com/uber-go/atomic/blob/3504dfaa1fa414923b1c8693f45d2f6931daf229/bool_ext.go#L40
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.

View File

@ -2,7 +2,6 @@ package abool
import (
"encoding/json"
"math"
"sync"
"sync/atomic"
"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) {
repeat := 10000
var wg sync.WaitGroup
@ -171,6 +141,22 @@ func TestRace(t *testing.T) {
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) {
for _, value := range []bool{true, false} {
// 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
}
func BenchmarkAtomicBoolToggle(b *testing.B) {
v := New()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = v.Toggle()
}
}
// Benchmark Read
func BenchmarkMutexRead(b *testing.B) {