Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
chans.go414 linesDownload Raw Back to typeparam
1// run2 3// Copyright 2021 The Go Authors. All rights reserved.4// Use of this source code is governed by a BSD-style5// license that can be found in the LICENSE file.6 7// Package chans provides utility functions for working with channels.8package main9 10import (11	"context"12	"fmt"13	"runtime"14	"sort"15	"sync"16	"time"17)18 19// _Equal reports whether two slices are equal: the same length and all20// elements equal. All floating point NaNs are considered equal.21func _SliceEqual[Elem comparable](s1, s2 []Elem) bool {22	if len(s1) != len(s2) {23		return false24	}25	for i, v1 := range s1 {26		v2 := s2[i]27		if v1 != v2 {28			isNaN := func(f Elem) bool { return f != f }29			if !isNaN(v1) || !isNaN(v2) {30				return false31			}32		}33	}34	return true35}36 37// _ReadAll reads from c until the channel is closed or the context is38// canceled, returning all the values read.39func _ReadAll[Elem any](ctx context.Context, c <-chan Elem) []Elem {40	var r []Elem41	for {42		select {43		case <-ctx.Done():44			return r45		case v, ok := <-c:46			if !ok {47				return r48			}49			r = append(r, v)50		}51	}52}53 54// _Merge merges two channels into a single channel.55// This will leave a goroutine running until either both channels are closed56// or the context is canceled, at which point the returned channel is closed.57func _Merge[Elem any](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem {58	r := make(chan Elem)59	go func(ctx context.Context, c1, c2 <-chan Elem, r chan<- Elem) {60		defer close(r)61		for c1 != nil || c2 != nil {62			select {63			case <-ctx.Done():64				return65			case v1, ok := <-c1:66				if ok {67					r <- v168				} else {69					c1 = nil70				}71			case v2, ok := <-c2:72				if ok {73					r <- v274				} else {75					c2 = nil76				}77			}78		}79	}(ctx, c1, c2, r)80	return r81}82 83// _Filter calls f on each value read from c. If f returns true the value84// is sent on the returned channel. This will leave a goroutine running85// until c is closed or the context is canceled, at which point the86// returned channel is closed.87func _Filter[Elem any](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem {88	r := make(chan Elem)89	go func(ctx context.Context, c <-chan Elem, f func(Elem) bool, r chan<- Elem) {90		defer close(r)91		for {92			select {93			case <-ctx.Done():94				return95			case v, ok := <-c:96				if !ok {97					return98				}99				if f(v) {100					r <- v101				}102			}103		}104	}(ctx, c, f, r)105	return r106}107 108// _Sink returns a channel that discards all values sent to it.109// This will leave a goroutine running until the context is canceled110// or the returned channel is closed.111func _Sink[Elem any](ctx context.Context) chan<- Elem {112	r := make(chan Elem)113	go func(ctx context.Context, r <-chan Elem) {114		for {115			select {116			case <-ctx.Done():117				return118			case _, ok := <-r:119				if !ok {120					return121				}122			}123		}124	}(ctx, r)125	return r126}127 128// An Exclusive is a value that may only be used by a single goroutine129// at a time. This is implemented using channels rather than a mutex.130type _Exclusive[Val any] struct {131	c chan Val132}133 134// _MakeExclusive makes an initialized exclusive value.135func _MakeExclusive[Val any](initial Val) *_Exclusive[Val] {136	r := &_Exclusive[Val]{137		c: make(chan Val, 1),138	}139	r.c <- initial140	return r141}142 143// _Acquire acquires the exclusive value for private use.144// It must be released using the Release method.145func (e *_Exclusive[Val]) Acquire() Val {146	return <-e.c147}148 149// TryAcquire attempts to acquire the value. The ok result reports whether150// the value was acquired. If the value is acquired, it must be released151// using the Release method.152func (e *_Exclusive[Val]) TryAcquire() (v Val, ok bool) {153	select {154	case r := <-e.c:155		return r, true156	default:157		return v, false158	}159}160 161// Release updates and releases the value.162// This method panics if the value has not been acquired.163func (e *_Exclusive[Val]) Release(v Val) {164	select {165	case e.c <- v:166	default:167		panic("_Exclusive Release without Acquire")168	}169}170 171// Ranger returns a Sender and a Receiver. The Receiver provides a172// Next method to retrieve values. The Sender provides a Send method173// to send values and a Close method to stop sending values. The Next174// method indicates when the Sender has been closed, and the Send175// method indicates when the Receiver has been freed.176//177// This is a convenient way to exit a goroutine sending values when178// the receiver stops reading them.179func _Ranger[Elem any]() (*_Sender[Elem], *_Receiver[Elem]) {180	c := make(chan Elem)181	d := make(chan struct{})182	s := &_Sender[Elem]{183		values: c,184		done:   d,185	}186	r := &_Receiver[Elem]{187		values: c,188		done:   d,189	}190	runtime.SetFinalizer(r, (*_Receiver[Elem]).finalize)191	return s, r192}193 194// A _Sender is used to send values to a Receiver.195type _Sender[Elem any] struct {196	values chan<- Elem197	done   <-chan struct{}198}199 200// Send sends a value to the receiver. It reports whether the value was sent.201// The value will not be sent if the context is closed or the receiver202// is freed.203func (s *_Sender[Elem]) Send(ctx context.Context, v Elem) bool {204	select {205	case <-ctx.Done():206		return false207	case s.values <- v:208		return true209	case <-s.done:210		return false211	}212}213 214// Close tells the receiver that no more values will arrive.215// After Close is called, the _Sender may no longer be used.216func (s *_Sender[Elem]) Close() {217	close(s.values)218}219 220// A _Receiver receives values from a _Sender.221type _Receiver[Elem any] struct {222	values <-chan Elem223	done   chan<- struct{}224}225 226// Next returns the next value from the channel. The bool result indicates227// whether the value is valid.228func (r *_Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) {229	select {230	case <-ctx.Done():231	case v, ok = <-r.values:232	}233	return v, ok234}235 236// finalize is a finalizer for the receiver.237func (r *_Receiver[Elem]) finalize() {238	close(r.done)239}240 241func TestReadAll() {242	c := make(chan int)243	go func() {244		c <- 4245		c <- 2246		c <- 5247		close(c)248	}()249	got := _ReadAll(context.Background(), c)250	want := []int{4, 2, 5}251	if !_SliceEqual(got, want) {252		panic(fmt.Sprintf("_ReadAll returned %v, want %v", got, want))253	}254}255 256func TestMerge() {257	c1 := make(chan int)258	c2 := make(chan int)259	go func() {260		c1 <- 1261		c1 <- 3262		c1 <- 5263		close(c1)264	}()265	go func() {266		c2 <- 2267		c2 <- 4268		c2 <- 6269		close(c2)270	}()271	ctx := context.Background()272	got := _ReadAll(ctx, _Merge(ctx, c1, c2))273	sort.Ints(got)274	want := []int{1, 2, 3, 4, 5, 6}275	if !_SliceEqual(got, want) {276		panic(fmt.Sprintf("_Merge returned %v, want %v", got, want))277	}278}279 280func TestFilter() {281	c := make(chan int)282	go func() {283		c <- 1284		c <- 2285		c <- 3286		close(c)287	}()288	even := func(i int) bool { return i%2 == 0 }289	ctx := context.Background()290	got := _ReadAll(ctx, _Filter(ctx, c, even))291	want := []int{2}292	if !_SliceEqual(got, want) {293		panic(fmt.Sprintf("_Filter returned %v, want %v", got, want))294	}295}296 297func TestSink() {298	c := _Sink[int](context.Background())299	after := time.NewTimer(time.Minute)300	defer after.Stop()301	send := func(v int) {302		select {303		case c <- v:304		case <-after.C:305			panic("timed out sending to _Sink")306		}307	}308	send(1)309	send(2)310	send(3)311	close(c)312}313 314func TestExclusive() {315	val := 0316	ex := _MakeExclusive(&val)317 318	var wg sync.WaitGroup319	f := func() {320		defer wg.Done()321		for i := 0; i < 10; i++ {322			p := ex.Acquire()323			(*p)++324			ex.Release(p)325		}326	}327 328	wg.Add(2)329	go f()330	go f()331 332	wg.Wait()333	if val != 20 {334		panic(fmt.Sprintf("after Acquire/Release loop got %d, want 20", val))335	}336}337 338func TestExclusiveTry() {339	s := ""340	ex := _MakeExclusive(&s)341	p, ok := ex.TryAcquire()342	if !ok {343		panic("TryAcquire failed")344	}345	*p = "a"346 347	var wg sync.WaitGroup348	wg.Add(1)349	go func() {350		defer wg.Done()351		_, ok := ex.TryAcquire()352		if ok {353			panic(fmt.Sprintf("TryAcquire succeeded unexpectedly"))354		}355	}()356	wg.Wait()357 358	ex.Release(p)359 360	p, ok = ex.TryAcquire()361	if !ok {362		panic(fmt.Sprintf("TryAcquire failed"))363	}364}365 366func TestRanger() {367	s, r := _Ranger[int]()368 369	ctx := context.Background()370	go func() {371		// Receive one value then exit.372		v, ok := r.Next(ctx)373		if !ok {374			panic(fmt.Sprintf("did not receive any values"))375		} else if v != 1 {376			panic(fmt.Sprintf("received %d, want 1", v))377		}378	}()379 380	c1 := make(chan bool)381	c2 := make(chan bool)382	go func() {383		defer close(c2)384		if !s.Send(ctx, 1) {385			panic(fmt.Sprintf("Send failed unexpectedly"))386		}387		close(c1)388		if s.Send(ctx, 2) {389			panic(fmt.Sprintf("Send succeeded unexpectedly"))390		}391	}()392 393	<-c1394 395	// Force a garbage collection to try to get the finalizers to run.396	runtime.GC()397 398	select {399	case <-c2:400	case <-time.After(time.Minute):401		panic("_Ranger Send should have failed, but timed out")402	}403}404 405func main() {406	TestReadAll()407	TestMerge()408	TestFilter()409	TestSink()410	TestExclusive()411	TestExclusiveTry()412	TestRanger()413}414 
codekingpro/portable-devtools · Team Ai