diff options
Diffstat (limited to 'test/typeparam/chansimp.dir/a.go')
-rw-r--r-- | test/typeparam/chansimp.dir/a.go | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/test/typeparam/chansimp.dir/a.go b/test/typeparam/chansimp.dir/a.go new file mode 100644 index 0000000..7321992 --- /dev/null +++ b/test/typeparam/chansimp.dir/a.go @@ -0,0 +1,232 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import ( + "context" + "runtime" +) + +// Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// ReadAll reads from c until the channel is closed or the context is +// canceled, returning all the values read. +func ReadAll[Elem any](ctx context.Context, c <-chan Elem) []Elem { + var r []Elem + for { + select { + case <-ctx.Done(): + return r + case v, ok := <-c: + if !ok { + return r + } + r = append(r, v) + } + } +} + +// Merge merges two channels into a single channel. +// This will leave a goroutine running until either both channels are closed +// or the context is canceled, at which point the returned channel is closed. +func Merge[Elem any](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem { + r := make(chan Elem) + go func(ctx context.Context, c1, c2 <-chan Elem, r chan<- Elem) { + defer close(r) + for c1 != nil || c2 != nil { + select { + case <-ctx.Done(): + return + case v1, ok := <-c1: + if ok { + r <- v1 + } else { + c1 = nil + } + case v2, ok := <-c2: + if ok { + r <- v2 + } else { + c2 = nil + } + } + } + }(ctx, c1, c2, r) + return r +} + +// Filter calls f on each value read from c. If f returns true the value +// is sent on the returned channel. This will leave a goroutine running +// until c is closed or the context is canceled, at which point the +// returned channel is closed. +func Filter[Elem any](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem { + r := make(chan Elem) + go func(ctx context.Context, c <-chan Elem, f func(Elem) bool, r chan<- Elem) { + defer close(r) + for { + select { + case <-ctx.Done(): + return + case v, ok := <-c: + if !ok { + return + } + if f(v) { + r <- v + } + } + } + }(ctx, c, f, r) + return r +} + +// Sink returns a channel that discards all values sent to it. +// This will leave a goroutine running until the context is canceled +// or the returned channel is closed. +func Sink[Elem any](ctx context.Context) chan<- Elem { + r := make(chan Elem) + go func(ctx context.Context, r <-chan Elem) { + for { + select { + case <-ctx.Done(): + return + case _, ok := <-r: + if !ok { + return + } + } + } + }(ctx, r) + return r +} + +// An Exclusive is a value that may only be used by a single goroutine +// at a time. This is implemented using channels rather than a mutex. +type Exclusive[Val any] struct { + c chan Val +} + +// MakeExclusive makes an initialized exclusive value. +func MakeExclusive[Val any](initial Val) *Exclusive[Val] { + r := &Exclusive[Val]{ + c: make(chan Val, 1), + } + r.c <- initial + return r +} + +// Acquire acquires the exclusive value for private use. +// It must be released using the Release method. +func (e *Exclusive[Val]) Acquire() Val { + return <-e.c +} + +// TryAcquire attempts to acquire the value. The ok result reports whether +// the value was acquired. If the value is acquired, it must be released +// using the Release method. +func (e *Exclusive[Val]) TryAcquire() (v Val, ok bool) { + select { + case r := <-e.c: + return r, true + default: + return v, false + } +} + +// Release updates and releases the value. +// This method panics if the value has not been acquired. +func (e *Exclusive[Val]) Release(v Val) { + select { + case e.c <- v: + default: + panic("Exclusive Release without Acquire") + } +} + +// Ranger returns a Sender and a Receiver. The Receiver provides a +// Next method to retrieve values. The Sender provides a Send method +// to send values and a Close method to stop sending values. The Next +// method indicates when the Sender has been closed, and the Send +// method indicates when the Receiver has been freed. +// +// This is a convenient way to exit a goroutine sending values when +// the receiver stops reading them. +func Ranger[Elem any]() (*Sender[Elem], *Receiver[Elem]) { + c := make(chan Elem) + d := make(chan struct{}) + s := &Sender[Elem]{ + values: c, + done: d, + } + r := &Receiver[Elem]{ + values: c, + done: d, + } + runtime.SetFinalizer(r, (*Receiver[Elem]).finalize) + return s, r +} + +// A Sender is used to send values to a Receiver. +type Sender[Elem any] struct { + values chan<- Elem + done <-chan struct{} +} + +// Send sends a value to the receiver. It reports whether the value was sent. +// The value will not be sent if the context is closed or the receiver +// is freed. +func (s *Sender[Elem]) Send(ctx context.Context, v Elem) bool { + select { + case <-ctx.Done(): + return false + case s.values <- v: + return true + case <-s.done: + return false + } +} + +// Close tells the receiver that no more values will arrive. +// After Close is called, the Sender may no longer be used. +func (s *Sender[Elem]) Close() { + close(s.values) +} + +// A Receiver receives values from a Sender. +type Receiver[Elem any] struct { + values <-chan Elem + done chan<- struct{} +} + +// Next returns the next value from the channel. The bool result indicates +// whether the value is valid. +func (r *Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) { + select { + case <-ctx.Done(): + case v, ok = <-r.values: + } + return v, ok +} + +// finalize is a finalizer for the receiver. +func (r *Receiver[Elem]) finalize() { + close(r.done) +} |