From 30943ded71e123886291ad393e55bfb6aa837df3 Mon Sep 17 00:00:00 2001 From: Chris Wendt Date: Wed, 8 Jun 2022 02:28:37 -0600 Subject: BIG change: generic Var[T], txVar, etc. --- stm_test.go | 74 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'stm_test.go') diff --git a/stm_test.go b/stm_test.go index 5c0ae31..fdf7af2 100644 --- a/stm_test.go +++ b/stm_test.go @@ -11,17 +11,17 @@ import ( ) func TestDecrement(t *testing.T) { - x := NewVar(1000) + x := NewVar[int](1000) for i := 0; i < 500; i++ { go Atomically(VoidOperation(func(tx *Tx) { - cur := tx.Get(x).(int) - tx.Set(x, cur-1) + cur := x.Get(tx) + x.Set(tx, cur-1) })) } done := make(chan struct{}) go func() { Atomically(VoidOperation(func(tx *Tx) { - tx.Assert(tx.Get(x) == 500) + tx.Assert(x.Get(tx) == 500) })) close(done) }() @@ -35,7 +35,7 @@ func TestDecrement(t *testing.T) { // read-only transaction aren't exempt from calling tx.inputsChanged func TestReadVerify(t *testing.T) { read := make(chan struct{}) - x, y := NewVar(1), NewVar(2) + x, y := NewVar[int](1), NewVar[int](2) // spawn a transaction that writes to x go func() { @@ -50,10 +50,10 @@ func TestReadVerify(t *testing.T) { // between the reads, causing this tx to retry. var x2, y2 int Atomically(VoidOperation(func(tx *Tx) { - x2 = tx.Get(x).(int) + x2 = x.Get(tx) read <- struct{}{} <-read // wait for other tx to complete - y2 = tx.Get(y).(int) + y2 = y.Get(tx) })) if x2 == 1 && y2 == 2 { t.Fatal("read was not verified") @@ -61,15 +61,15 @@ func TestReadVerify(t *testing.T) { } func TestRetry(t *testing.T) { - x := NewVar(10) + x := NewVar[int](10) // spawn 10 transactions, one every 10 milliseconds. This will decrement x // to 0 over the course of 100 milliseconds. go func() { for i := 0; i < 10; i++ { time.Sleep(10 * time.Millisecond) Atomically(VoidOperation(func(tx *Tx) { - cur := tx.Get(x).(int) - tx.Set(x, cur-1) + cur := x.Get(tx) + x.Set(tx, cur-1) })) } }() @@ -77,7 +77,7 @@ func TestRetry(t *testing.T) { // retry. This should result in no more than 1 retry per transaction. retry := 0 Atomically(VoidOperation(func(tx *Tx) { - cur := tx.Get(x).(int) + cur := x.Get(tx) if cur != 0 { retry++ tx.Retry() @@ -93,16 +93,16 @@ func TestVerify(t *testing.T) { type foo struct { i int } - x := NewVar(&foo{3}) + x := NewVar[*foo](&foo{3}) read := make(chan struct{}) // spawn a transaction that modifies x go func() { Atomically(VoidOperation(func(tx *Tx) { <-read - rx := tx.Get(x).(*foo) + rx := x.Get(tx) rx.i = 7 - tx.Set(x, rx) + x.Set(tx, rx) })) read <- struct{}{} // other tx should retry, so we need to read/send again @@ -113,7 +113,7 @@ func TestVerify(t *testing.T) { // between the reads, causing this tx to retry. var i int Atomically(VoidOperation(func(tx *Tx) { - f := tx.Get(x).(*foo) + f := x.Get(tx) i = f.i read <- struct{}{} <-read // wait for other tx to complete @@ -128,9 +128,9 @@ func TestSelect(t *testing.T) { require.Panics(t, func() { Atomically(Select()) }) // with one arg, Select adds no effect - x := NewVar(2) + x := NewVar[int](2) Atomically(Select(VoidOperation(func(tx *Tx) { - tx.Assert(tx.Get(x).(int) == 2) + tx.Assert(x.Get(tx) == 2) }))) picked := Atomically(Select( @@ -146,7 +146,7 @@ func TestSelect(t *testing.T) { func(tx *Tx) interface{} { return 3 }, - )).(int) + )) assert.EqualValues(t, 2, picked) } @@ -178,20 +178,20 @@ func TestPanic(t *testing.T) { func TestReadWritten(t *testing.T) { // reading a variable written in the same transaction should return the // previously written value - x := NewVar(3) + x := NewVar[int](3) Atomically(VoidOperation(func(tx *Tx) { - tx.Set(x, 5) - tx.Assert(tx.Get(x).(int) == 5) + x.Set(tx, 5) + tx.Assert(x.Get(tx) == 5) })) } func TestAtomicSetRetry(t *testing.T) { // AtomicSet should cause waiting transactions to retry - x := NewVar(3) + x := NewVar[int](3) done := make(chan struct{}) go func() { Atomically(VoidOperation(func(tx *Tx) { - tx.Assert(tx.Get(x).(int) == 5) + tx.Assert(x.Get(tx) == 5) })) done <- struct{}{} }() @@ -206,21 +206,21 @@ func TestAtomicSetRetry(t *testing.T) { func testPingPong(t testing.TB, n int, afterHit func(string)) { ball := NewBuiltinEqVar(false) - doneVar := NewVar(false) - hits := NewVar(0) - ready := NewVar(true) // The ball is ready for hitting. + doneVar := NewVar[bool](false) + hits := NewVar[int](0) + ready := NewVar[bool](true) // The ball is ready for hitting. var wg sync.WaitGroup - bat := func(from, to interface{}, noise string) { + bat := func(from, to bool, noise string) { defer wg.Done() for !Atomically(func(tx *Tx) interface{} { - if tx.Get(doneVar).(bool) { + if doneVar.Get(tx) { return true } - tx.Assert(tx.Get(ready).(bool)) - if tx.Get(ball) == from { - tx.Set(ball, to) - tx.Set(hits, tx.Get(hits).(int)+1) - tx.Set(ready, false) + tx.Assert(ready.Get(tx)) + if ball.Get(tx) == from { + ball.Set(tx, to) + hits.Set(tx, hits.Get(tx)+1) + ready.Set(tx, false) return false } return tx.Retry() @@ -233,8 +233,8 @@ func testPingPong(t testing.TB, n int, afterHit func(string)) { go bat(false, true, "ping!") go bat(true, false, "pong!") Atomically(VoidOperation(func(tx *Tx) { - tx.Assert(tx.Get(hits).(int) >= n) - tx.Set(doneVar, true) + tx.Assert(hits.Get(tx) >= n) + doneVar.Set(tx, true) })) wg.Wait() } @@ -253,7 +253,7 @@ func TestSleepingBeauty(t *testing.T) { } //func TestRetryStack(t *testing.T) { -// v := NewVar(nil) +// v := NewVar[int](nil) // go func() { // i := 0 // for { @@ -266,7 +266,7 @@ func TestSleepingBeauty(t *testing.T) { // ret := func() { // defer Atomically(nil) // } -// tx.Get(v) +// v.Get(tx) // tx.Assert(false) // return ret // }) -- cgit v1.2.3 From 8d82a394042feb858f8b8b40f199f9ede5cc1b83 Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Sat, 4 Sep 2021 21:09:25 +1000 Subject: Make Operation generic From https://github.com/anacrolix/stm/commit/80e033aa1f2218b83fb5891671ed795de72e19d5 --- funcs.go | 23 +++++++++++------------ retry.go | 2 +- stm_test.go | 15 ++++++++------- tx.go | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) (limited to 'stm_test.go') diff --git a/funcs.go b/funcs.go index 3336c71..54576ea 100644 --- a/funcs.go +++ b/funcs.go @@ -39,7 +39,7 @@ func newTx() *Tx { return tx } -func WouldBlock(fn Operation) (block bool) { +func WouldBlock[R any](fn Operation[R]) (block bool) { tx := newTx() tx.reset() _, block = catchRetry(fn, tx) @@ -51,7 +51,7 @@ func WouldBlock(fn Operation) (block bool) { } // Atomically executes the atomic function fn. -func Atomically(op Operation) interface{} { +func Atomically[R any](op Operation[R]) R { expvars.Add("atomically", 1) // run the transaction tx := newTx() @@ -116,20 +116,19 @@ func AtomicSet[T any](v *Var[T], val interface{}) { // Compose is a helper function that composes multiple transactions into a // single transaction. -func Compose(fns ...Operation) Operation { - return func(tx *Tx) interface{} { +func Compose[R any](fns ...Operation[R]) Operation[struct{}] { + return VoidOperation(func(tx *Tx) { for _, f := range fns { f(tx) } - return nil - } + }) } // Select runs the supplied functions in order. Execution stops when a // function succeeds without calling Retry. If no functions succeed, the // entire selection will be retried. -func Select(fns ...Operation) Operation { - return func(tx *Tx) interface{} { +func Select[R any](fns ...Operation[R]) Operation[R] { + return func(tx *Tx) R { switch len(fns) { case 0: // empty Select blocks forever @@ -154,12 +153,12 @@ func Select(fns ...Operation) Operation { } } -type Operation func(*Tx) interface{} +type Operation[R any] func(*Tx) R -func VoidOperation(f func(*Tx)) Operation { - return func(tx *Tx) interface{} { +func VoidOperation(f func(*Tx)) Operation[struct{}] { + return func(tx *Tx) struct{} { f(tx) - return nil + return struct{}{} } } diff --git a/retry.go b/retry.go index 1997b18..1adcfd0 100644 --- a/retry.go +++ b/retry.go @@ -11,7 +11,7 @@ var retries = pprof.NewProfile("stmRetries") var retry = &struct{}{} // catchRetry returns true if fn calls tx.Retry. -func catchRetry(fn Operation, tx *Tx) (result interface{}, gotRetry bool) { +func catchRetry[R any](fn Operation[R], tx *Tx) (result R, gotRetry bool) { defer func() { if r := recover(); r == retry { gotRetry = true diff --git a/stm_test.go b/stm_test.go index fdf7af2..4103563 100644 --- a/stm_test.go +++ b/stm_test.go @@ -125,7 +125,7 @@ func TestVerify(t *testing.T) { func TestSelect(t *testing.T) { // empty Select should panic - require.Panics(t, func() { Atomically(Select()) }) + require.Panics(t, func() { Atomically(Select[struct{}]()) }) // with one arg, Select adds no effect x := NewVar[int](2) @@ -135,15 +135,16 @@ func TestSelect(t *testing.T) { picked := Atomically(Select( // always blocks; should never be selected - VoidOperation(func(tx *Tx) { + func(tx *Tx)int { tx.Retry() - }), + panic("unreachable") + }, // always succeeds; should always be selected - func(tx *Tx) interface{} { + func(tx *Tx) int { return 2 }, // always succeeds; should never be selected - func(tx *Tx) interface{} { + func(tx *Tx) int { return 3 }, )) @@ -152,9 +153,9 @@ func TestSelect(t *testing.T) { func TestCompose(t *testing.T) { nums := make([]int, 100) - fns := make([]Operation, 100) + fns := make([]Operation[struct{}], 100) for i := range fns { - fns[i] = func(x int) Operation { + fns[i] = func(x int) Operation[struct{}] { return VoidOperation(func(*Tx) { nums[x] = x }) }(i) // capture loop var } diff --git a/tx.go b/tx.go index 0d69498..2020308 100644 --- a/tx.go +++ b/tx.go @@ -114,7 +114,7 @@ type txProfileValue struct { // Retry aborts the transaction and retries it when a Var changes. You can return from this method // to satisfy return values, but it should never actually return anything as it panics internally. -func (tx *Tx) Retry() interface{} { +func (tx *Tx) Retry() struct{} { retries.Add(txProfileValue{tx, tx.numRetryValues}, 1) tx.numRetryValues++ panic(retry) -- cgit v1.2.3 From 2ef3a53065a49ba3238203484588f1f72ccf25fd Mon Sep 17 00:00:00 2001 From: Chris Wendt Date: Wed, 8 Jun 2022 03:16:02 -0600 Subject: remove unnecessary type parameters --- bench_test.go | 8 ++++---- cmd/santa-example/main.go | 8 ++++---- doc_test.go | 2 +- external_test.go | 4 ++-- rate/ratelimit.go | 4 ++-- stm_test.go | 22 +++++++++++----------- stmutil/context.go | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) (limited to 'stm_test.go') diff --git a/bench_test.go b/bench_test.go index 0b84715..0d40caf 100644 --- a/bench_test.go +++ b/bench_test.go @@ -8,14 +8,14 @@ import ( ) func BenchmarkAtomicGet(b *testing.B) { - x := NewVar[int](0) + x := NewVar(0) for i := 0; i < b.N; i++ { AtomicGet(x) } } func BenchmarkAtomicSet(b *testing.B) { - x := NewVar[int](0) + x := NewVar(0) for i := 0; i < b.N; i++ { AtomicSet(x, 0) } @@ -24,7 +24,7 @@ func BenchmarkAtomicSet(b *testing.B) { func BenchmarkIncrementSTM(b *testing.B) { for i := 0; i < b.N; i++ { // spawn 1000 goroutines that each increment x by 1 - x := NewVar[int](0) + x := NewVar(0) for i := 0; i < 1000; i++ { go Atomically(VoidOperation(func(tx *Tx) { cur := x.Get(tx) @@ -83,7 +83,7 @@ func BenchmarkReadVarSTM(b *testing.B) { for i := 0; i < b.N; i++ { var wg sync.WaitGroup wg.Add(1000) - x := NewVar[int](0) + x := NewVar(0) for i := 0; i < 1000; i++ { go func() { AtomicGet(x) diff --git a/cmd/santa-example/main.go b/cmd/santa-example/main.go index 1a93ae4..dcc8067 100644 --- a/cmd/santa-example/main.go +++ b/cmd/santa-example/main.go @@ -64,7 +64,7 @@ func (g gate) operate() { func newGate(capacity int) gate { return gate{ capacity: capacity, - remaining: stm.NewVar[int](0), // gate starts out closed + remaining: stm.NewVar(0), // gate starts out closed } } @@ -77,9 +77,9 @@ type group struct { func newGroup(capacity int) *group { return &group{ capacity: capacity, - remaining: stm.NewVar[int](capacity), // group starts out with full capacity - gate1: stm.NewVar[gate](newGate(capacity)), - gate2: stm.NewVar[gate](newGate(capacity)), + remaining: stm.NewVar(capacity), // group starts out with full capacity + gate1: stm.NewVar(newGate(capacity)), + gate2: stm.NewVar(newGate(capacity)), } } diff --git a/doc_test.go b/doc_test.go index 670d07b..ae1af9a 100644 --- a/doc_test.go +++ b/doc_test.go @@ -6,7 +6,7 @@ import ( func Example() { // create a shared variable - n := stm.NewVar[int](3) + n := stm.NewVar(3) // read a variable var v int diff --git a/external_test.go b/external_test.go index d0f5ecf..201712d 100644 --- a/external_test.go +++ b/external_test.go @@ -99,9 +99,9 @@ func BenchmarkInvertedThunderingHerd(b *testing.B) { for i := 0; i < b.N; i++ { done := stm.NewBuiltinEqVar(false) tokens := stm.NewBuiltinEqVar(0) - pending := stm.NewVar[stmutil.Settish](stmutil.NewSet()) + pending := stm.NewVar(stmutil.NewSet()) for range iter.N(1000) { - ready := stm.NewVar[bool](false) + ready := stm.NewVar(false) stm.Atomically(stm.VoidOperation(func(tx *stm.Tx) { pending.Set(tx, pending.Get(tx).Add(ready)) })) diff --git a/rate/ratelimit.go b/rate/ratelimit.go index 7fde1ce..6645e04 100644 --- a/rate/ratelimit.go +++ b/rate/ratelimit.go @@ -36,9 +36,9 @@ func Every(interval time.Duration) Limit { func NewLimiter(rate Limit, burst numTokens) *Limiter { rl := &Limiter{ - max: stm.NewVar[int](burst), + max: stm.NewVar(burst), cur: stm.NewBuiltinEqVar(burst), - lastAdd: stm.NewVar[time.Time](time.Now()), + lastAdd: stm.NewVar(time.Now()), rate: rate, } if rate != Inf { diff --git a/stm_test.go b/stm_test.go index 4103563..8726d40 100644 --- a/stm_test.go +++ b/stm_test.go @@ -11,7 +11,7 @@ import ( ) func TestDecrement(t *testing.T) { - x := NewVar[int](1000) + x := NewVar(1000) for i := 0; i < 500; i++ { go Atomically(VoidOperation(func(tx *Tx) { cur := x.Get(tx) @@ -35,7 +35,7 @@ func TestDecrement(t *testing.T) { // read-only transaction aren't exempt from calling tx.inputsChanged func TestReadVerify(t *testing.T) { read := make(chan struct{}) - x, y := NewVar[int](1), NewVar[int](2) + x, y := NewVar(1), NewVar(2) // spawn a transaction that writes to x go func() { @@ -61,7 +61,7 @@ func TestReadVerify(t *testing.T) { } func TestRetry(t *testing.T) { - x := NewVar[int](10) + x := NewVar(10) // spawn 10 transactions, one every 10 milliseconds. This will decrement x // to 0 over the course of 100 milliseconds. go func() { @@ -93,7 +93,7 @@ func TestVerify(t *testing.T) { type foo struct { i int } - x := NewVar[*foo](&foo{3}) + x := NewVar(&foo{3}) read := make(chan struct{}) // spawn a transaction that modifies x @@ -128,14 +128,14 @@ func TestSelect(t *testing.T) { require.Panics(t, func() { Atomically(Select[struct{}]()) }) // with one arg, Select adds no effect - x := NewVar[int](2) + x := NewVar(2) Atomically(Select(VoidOperation(func(tx *Tx) { tx.Assert(x.Get(tx) == 2) }))) picked := Atomically(Select( // always blocks; should never be selected - func(tx *Tx)int { + func(tx *Tx) int { tx.Retry() panic("unreachable") }, @@ -179,7 +179,7 @@ func TestPanic(t *testing.T) { func TestReadWritten(t *testing.T) { // reading a variable written in the same transaction should return the // previously written value - x := NewVar[int](3) + x := NewVar(3) Atomically(VoidOperation(func(tx *Tx) { x.Set(tx, 5) tx.Assert(x.Get(tx) == 5) @@ -188,7 +188,7 @@ func TestReadWritten(t *testing.T) { func TestAtomicSetRetry(t *testing.T) { // AtomicSet should cause waiting transactions to retry - x := NewVar[int](3) + x := NewVar(3) done := make(chan struct{}) go func() { Atomically(VoidOperation(func(tx *Tx) { @@ -207,9 +207,9 @@ func TestAtomicSetRetry(t *testing.T) { func testPingPong(t testing.TB, n int, afterHit func(string)) { ball := NewBuiltinEqVar(false) - doneVar := NewVar[bool](false) - hits := NewVar[int](0) - ready := NewVar[bool](true) // The ball is ready for hitting. + doneVar := NewVar(false) + hits := NewVar(0) + ready := NewVar(true) // The ball is ready for hitting. var wg sync.WaitGroup bat := func(from, to bool, noise string) { defer wg.Done() diff --git a/stmutil/context.go b/stmutil/context.go index 9d23e12..6f8ba9b 100644 --- a/stmutil/context.go +++ b/stmutil/context.go @@ -26,7 +26,7 @@ func ContextDoneVar(ctx context.Context) (*stm.Var[bool], func()) { v := stm.NewBuiltinEqVar(true) return v, func() {} } - v := stm.NewVar[bool](false) + v := stm.NewVar(false) go func() { <-ctx.Done() stm.AtomicSet(v, true) -- cgit v1.2.3 From e6ac933d42b3b4a8ffd891b205ba48f0c1e278a4 Mon Sep 17 00:00:00 2001 From: Chris Wendt Date: Wed, 8 Jun 2022 03:27:33 -0600 Subject: replace "interface{}" with "any" --- README.md | 2 +- external_test.go | 2 +- funcs.go | 6 +++--- stm_test.go | 8 ++++---- stmutil/containers.go | 54 +++++++++++++++++++++++++-------------------------- tx.go | 4 ++-- var-value.go | 12 ++++++------ var.go | 4 ++-- 8 files changed, 46 insertions(+), 46 deletions(-) (limited to 'stm_test.go') diff --git a/README.md b/README.md index ba770d9..07e9952 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ See [cmd/santa-example/main.go](cmd/santa-example/main.go) for a more complex ex ## Pointers -Note that `Operation` now returns a value of type `interface{}`, which isn't included in the +Note that `Operation` now returns a value of type `any`, which isn't included in the examples throughout the documentation yet. See the type signatures for `Atomically` and `Operation`. Be very careful when managing pointers inside transactions! (This includes diff --git a/external_test.go b/external_test.go index a56aeee..abdf544 100644 --- a/external_test.go +++ b/external_test.go @@ -132,7 +132,7 @@ func BenchmarkInvertedThunderingHerd(b *testing.B) { for stm.Atomically(func(tx *stm.Tx) bool { tx.Assert(tokens.Get(tx) > 0) tokens.Set(tx, tokens.Get(tx)-1) - pending.Get(tx).Range(func(i interface{}) bool { + pending.Get(tx).Range(func(i any) bool { ready := i.(*stm.Var[bool]) if !ready.Get(tx) { ready.Set(tx, true) diff --git a/funcs.go b/funcs.go index c3a597b..07d35ec 100644 --- a/funcs.go +++ b/funcs.go @@ -8,11 +8,11 @@ import ( ) var ( - txPool = sync.Pool{New: func() interface{} { + txPool = sync.Pool{New: func() any { expvars.Add("new txs", 1) tx := &Tx{ reads: make(map[txVar]VarValue), - writes: make(map[txVar]interface{}), + writes: make(map[txVar]any), watching: make(map[txVar]struct{}), } tx.cond.L = &tx.mu @@ -138,7 +138,7 @@ func Select[R any](fns ...Operation[R]) Operation[R] { return fns[0](tx) default: oldWrites := tx.writes - tx.writes = make(map[txVar]interface{}, len(oldWrites)) + tx.writes = make(map[txVar]any, len(oldWrites)) for k, v := range oldWrites { tx.writes[k] = v } diff --git a/stm_test.go b/stm_test.go index 8726d40..5ed1b70 100644 --- a/stm_test.go +++ b/stm_test.go @@ -170,7 +170,7 @@ func TestCompose(t *testing.T) { func TestPanic(t *testing.T) { // normal panics should escape Atomically assert.PanicsWithValue(t, "foo", func() { - Atomically(func(*Tx) interface{} { + Atomically(func(*Tx) any { panic("foo") }) }) @@ -213,7 +213,7 @@ func testPingPong(t testing.TB, n int, afterHit func(string)) { var wg sync.WaitGroup bat := func(from, to bool, noise string) { defer wg.Done() - for !Atomically(func(tx *Tx) interface{} { + for !Atomically(func(tx *Tx) any { if doneVar.Get(tx) { return true } @@ -246,7 +246,7 @@ func TestPingPong(t *testing.T) { func TestSleepingBeauty(t *testing.T) { require.Panics(t, func() { - Atomically(func(tx *Tx) interface{} { + Atomically(func(tx *Tx) any { tx.Assert(false) return nil }) @@ -262,7 +262,7 @@ func TestSleepingBeauty(t *testing.T) { // i++ // } // }() -// Atomically(func(tx *Tx) interface{} { +// Atomically(func(tx *Tx) any { // debug.PrintStack() // ret := func() { // defer Atomically(nil) diff --git a/stmutil/containers.go b/stmutil/containers.go index e0b532d..c7a4a49 100644 --- a/stmutil/containers.go +++ b/stmutil/containers.go @@ -9,10 +9,10 @@ import ( ) type Settish interface { - Add(interface{}) Settish - Delete(interface{}) Settish - Contains(interface{}) bool - Range(func(interface{}) bool) + Add(any) Settish + Delete(any) Settish + Contains(any) bool + Range(func(any) bool) iter.Iterable Len() int } @@ -23,11 +23,11 @@ type mapToSet struct { type interhash struct{} -func (interhash) Hash(x interface{}) uint32 { +func (interhash) Hash(x any) uint32 { return uint32(nilinterhash(unsafe.Pointer(&x), 0)) } -func (interhash) Equal(i, j interface{}) bool { +func (interhash) Equal(i, j any) bool { return i == j } @@ -39,12 +39,12 @@ func NewSortedSet(lesser lessFunc) Settish { return mapToSet{NewSortedMap(lesser)} } -func (s mapToSet) Add(x interface{}) Settish { +func (s mapToSet) Add(x any) Settish { s.m = s.m.Set(x, nil) return s } -func (s mapToSet) Delete(x interface{}) Settish { +func (s mapToSet) Delete(x any) Settish { s.m = s.m.Delete(x) return s } @@ -53,13 +53,13 @@ func (s mapToSet) Len() int { return s.m.Len() } -func (s mapToSet) Contains(x interface{}) bool { +func (s mapToSet) Contains(x any) bool { _, ok := s.m.Get(x) return ok } -func (s mapToSet) Range(f func(interface{}) bool) { - s.m.Range(func(k, _ interface{}) bool { +func (s mapToSet) Range(f func(any) bool) { + s.m.Range(func(k, _ any) bool { return f(k) }) } @@ -78,17 +78,17 @@ func NewMap() Mappish { var _ Mappish = Map{} -func (m Map) Delete(x interface{}) Mappish { +func (m Map) Delete(x any) Mappish { m.Map = m.Map.Delete(x) return m } -func (m Map) Set(key, value interface{}) Mappish { +func (m Map) Set(key, value any) Mappish { m.Map = m.Map.Set(key, value) return m } -func (sm Map) Range(f func(key, value interface{}) bool) { +func (sm Map) Range(f func(key, value any) bool) { iter := sm.Map.Iterator() for !iter.Done() { if !f(iter.Next()) { @@ -98,7 +98,7 @@ func (sm Map) Range(f func(key, value interface{}) bool) { } func (sm Map) Iter(cb iter.Callback) { - sm.Range(func(key, _ interface{}) bool { + sm.Range(func(key, _ any) bool { return cb(key) }) } @@ -107,17 +107,17 @@ type SortedMap struct { *immutable.SortedMap } -func (sm SortedMap) Set(key, value interface{}) Mappish { +func (sm SortedMap) Set(key, value any) Mappish { sm.SortedMap = sm.SortedMap.Set(key, value) return sm } -func (sm SortedMap) Delete(key interface{}) Mappish { +func (sm SortedMap) Delete(key any) Mappish { sm.SortedMap = sm.SortedMap.Delete(key) return sm } -func (sm SortedMap) Range(f func(key, value interface{}) bool) { +func (sm SortedMap) Range(f func(key, value any) bool) { iter := sm.SortedMap.Iterator() for !iter.Done() { if !f(iter.Next()) { @@ -127,18 +127,18 @@ func (sm SortedMap) Range(f func(key, value interface{}) bool) { } func (sm SortedMap) Iter(cb iter.Callback) { - sm.Range(func(key, _ interface{}) bool { + sm.Range(func(key, _ any) bool { return cb(key) }) } -type lessFunc func(l, r interface{}) bool +type lessFunc func(l, r any) bool type comparer struct { less lessFunc } -func (me comparer) Compare(i, j interface{}) int { +func (me comparer) Compare(i, j any) int { if me.less(i, j) { return -1 } else if me.less(j, i) { @@ -155,15 +155,15 @@ func NewSortedMap(less lessFunc) Mappish { } type Mappish interface { - Set(key, value interface{}) Mappish - Delete(key interface{}) Mappish - Get(key interface{}) (interface{}, bool) - Range(func(_, _ interface{}) bool) + Set(key, value any) Mappish + Delete(key any) Mappish + Get(key any) (any, bool) + Range(func(_, _ any) bool) Len() int iter.Iterable } -func GetLeft(l, _ interface{}) interface{} { +func GetLeft(l, _ any) any { return l } @@ -171,7 +171,7 @@ func GetLeft(l, _ interface{}) interface{} { //go:linkname nilinterhash runtime.nilinterhash func nilinterhash(p unsafe.Pointer, h uintptr) uintptr -func interfaceHash(x interface{}) uint32 { +func interfaceHash(x any) uint32 { return uint32(nilinterhash(unsafe.Pointer(&x), 0)) } diff --git a/tx.go b/tx.go index 4542e61..825ff01 100644 --- a/tx.go +++ b/tx.go @@ -11,7 +11,7 @@ import ( type txVar interface { getValue() *atomic.Value[VarValue] - changeValue(interface{}) + changeValue(any) getWatchers() *sync.Map getLock() *sync.Mutex } @@ -19,7 +19,7 @@ type txVar interface { // A Tx represents an atomic transaction. type Tx struct { reads map[txVar]VarValue - writes map[txVar]interface{} + writes map[txVar]any watching map[txVar]struct{} locks txLocks mu sync.Mutex diff --git a/var-value.go b/var-value.go index f4921f3..3518bf6 100644 --- a/var-value.go +++ b/var-value.go @@ -1,8 +1,8 @@ package stm type VarValue interface { - Set(interface{}) VarValue - Get() interface{} + Set(any) VarValue + Get() any Changed(VarValue) bool } @@ -13,14 +13,14 @@ type versionedValue[T any] struct { version version } -func (me versionedValue[T]) Set(newValue interface{}) VarValue { +func (me versionedValue[T]) Set(newValue any) VarValue { return versionedValue[T]{ value: newValue.(T), version: me.version + 1, } } -func (me versionedValue[T]) Get() interface{} { +func (me versionedValue[T]) Get() any { return me.value } @@ -39,13 +39,13 @@ func (me customVarValue[T]) Changed(other VarValue) bool { return me.changed(me.value, other.(customVarValue[T]).value) } -func (me customVarValue[T]) Set(newValue interface{}) VarValue { +func (me customVarValue[T]) Set(newValue any) VarValue { return customVarValue[T]{ value: newValue.(T), changed: me.changed, } } -func (me customVarValue[T]) Get() interface{} { +func (me customVarValue[T]) Get() any { return me.value } diff --git a/var.go b/var.go index 2354d96..ec6a81e 100644 --- a/var.go +++ b/var.go @@ -25,7 +25,7 @@ func (v *Var[T]) getLock() *sync.Mutex { return &v.mu } -func (v *Var[T]) changeValue(new interface{}) { +func (v *Var[T]) changeValue(new any) { old := v.value.Load() newVarValue := old.Set(new) v.value.Store(newVarValue) @@ -35,7 +35,7 @@ func (v *Var[T]) changeValue(new interface{}) { } func (v *Var[T]) wakeWatchers(new VarValue) { - v.watchers.Range(func(k, _ interface{}) bool { + v.watchers.Range(func(k, _ any) bool { tx := k.(*Tx) // We have to lock here to ensure that the Tx is waiting before we signal it. Otherwise we // could signal it before it goes to sleep and it will miss the notification. -- cgit v1.2.3