Initial commit: Go 1.23 release state
This commit is contained in:
87
test/chan/doubleselect.go
Normal file
87
test/chan/doubleselect.go
Normal file
@@ -0,0 +1,87 @@
|
||||
// run
|
||||
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Test the situation in which two cases of a select can
|
||||
// both end up running. See http://codereview.appspot.com/180068.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var iterations *int = flag.Int("n", 100000, "number of iterations")
|
||||
|
||||
// sender sends a counter to one of four different channels. If two
|
||||
// cases both end up running in the same iteration, the same value will be sent
|
||||
// to two different channels.
|
||||
func sender(n int, c1, c2, c3, c4 chan<- int) {
|
||||
defer close(c1)
|
||||
defer close(c2)
|
||||
defer close(c3)
|
||||
defer close(c4)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
select {
|
||||
case c1 <- i:
|
||||
case c2 <- i:
|
||||
case c3 <- i:
|
||||
case c4 <- i:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mux receives the values from sender and forwards them onto another channel.
|
||||
// It would be simpler to just have sender's four cases all be the same
|
||||
// channel, but this doesn't actually trigger the bug.
|
||||
func mux(out chan<- int, in <-chan int, done chan<- bool) {
|
||||
for v := range in {
|
||||
out <- v
|
||||
}
|
||||
done <- true
|
||||
}
|
||||
|
||||
// recver gets a steam of values from the four mux's and checks for duplicates.
|
||||
func recver(in <-chan int) {
|
||||
seen := make(map[int]bool)
|
||||
|
||||
for v := range in {
|
||||
if _, ok := seen[v]; ok {
|
||||
println("got duplicate value: ", v)
|
||||
panic("fail")
|
||||
}
|
||||
seen[v] = true
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(2)
|
||||
|
||||
flag.Parse()
|
||||
c1 := make(chan int)
|
||||
c2 := make(chan int)
|
||||
c3 := make(chan int)
|
||||
c4 := make(chan int)
|
||||
done := make(chan bool)
|
||||
cmux := make(chan int)
|
||||
go sender(*iterations, c1, c2, c3, c4)
|
||||
go mux(cmux, c1, done)
|
||||
go mux(cmux, c2, done)
|
||||
go mux(cmux, c3, done)
|
||||
go mux(cmux, c4, done)
|
||||
go func() {
|
||||
<-done
|
||||
<-done
|
||||
<-done
|
||||
<-done
|
||||
close(cmux)
|
||||
}()
|
||||
// We keep the recver because it might catch more bugs in the future.
|
||||
// However, the result of the bug linked to at the top is that we'll
|
||||
// end up panicking with: "throw: bad g->status in ready".
|
||||
recver(cmux)
|
||||
}
|
||||
56
test/chan/fifo.go
Normal file
56
test/chan/fifo.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// run
|
||||
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Test that unbuffered channels act as pure fifos.
|
||||
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
const N = 10
|
||||
|
||||
func AsynchFifo() {
|
||||
ch := make(chan int, N)
|
||||
for i := 0; i < N; i++ {
|
||||
ch <- i
|
||||
}
|
||||
for i := 0; i < N; i++ {
|
||||
if <-ch != i {
|
||||
print("bad receive\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Chain(ch <-chan int, val int, in <-chan int, out chan<- int) {
|
||||
<-in
|
||||
if <-ch != val {
|
||||
panic(val)
|
||||
}
|
||||
out <- 1
|
||||
}
|
||||
|
||||
// thread together a daisy chain to read the elements in sequence
|
||||
func SynchFifo() {
|
||||
ch := make(chan int)
|
||||
in := make(chan int)
|
||||
start := in
|
||||
for i := 0; i < N; i++ {
|
||||
out := make(chan int)
|
||||
go Chain(ch, i, in, out)
|
||||
in = out
|
||||
}
|
||||
start <- 0
|
||||
for i := 0; i < N; i++ {
|
||||
ch <- i
|
||||
}
|
||||
<-in
|
||||
}
|
||||
|
||||
func main() {
|
||||
AsynchFifo()
|
||||
SynchFifo()
|
||||
}
|
||||
41
test/chan/goroutines.go
Normal file
41
test/chan/goroutines.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// run
|
||||
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Torture test for goroutines.
|
||||
// Make a lot of goroutines, threaded together, and tear them down cleanly.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func f(left, right chan int) {
|
||||
left <- <-right
|
||||
}
|
||||
|
||||
func main() {
|
||||
var n = 10000
|
||||
if len(os.Args) > 1 {
|
||||
var err error
|
||||
n, err = strconv.Atoi(os.Args[1])
|
||||
if err != nil {
|
||||
print("bad arg\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
leftmost := make(chan int)
|
||||
right := leftmost
|
||||
left := leftmost
|
||||
for i := 0; i < n; i++ {
|
||||
right = make(chan int)
|
||||
go f(left, right)
|
||||
left = right
|
||||
}
|
||||
go func(c chan int) { c <- 1 }(right)
|
||||
<-leftmost
|
||||
}
|
||||
282
test/chan/nonblock.go
Normal file
282
test/chan/nonblock.go
Normal file
@@ -0,0 +1,282 @@
|
||||
// run
|
||||
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Test channel operations that test for blocking.
|
||||
// Use several sizes and types of operands.
|
||||
|
||||
package main
|
||||
|
||||
import "runtime"
|
||||
import "time"
|
||||
|
||||
func i32receiver(c chan int32, strobe chan bool) {
|
||||
if <-c != 123 {
|
||||
panic("i32 value")
|
||||
}
|
||||
strobe <- true
|
||||
}
|
||||
|
||||
func i32sender(c chan int32, strobe chan bool) {
|
||||
c <- 234
|
||||
strobe <- true
|
||||
}
|
||||
|
||||
func i64receiver(c chan int64, strobe chan bool) {
|
||||
if <-c != 123456 {
|
||||
panic("i64 value")
|
||||
}
|
||||
strobe <- true
|
||||
}
|
||||
|
||||
func i64sender(c chan int64, strobe chan bool) {
|
||||
c <- 234567
|
||||
strobe <- true
|
||||
}
|
||||
|
||||
func breceiver(c chan bool, strobe chan bool) {
|
||||
if !<-c {
|
||||
panic("b value")
|
||||
}
|
||||
strobe <- true
|
||||
}
|
||||
|
||||
func bsender(c chan bool, strobe chan bool) {
|
||||
c <- true
|
||||
strobe <- true
|
||||
}
|
||||
|
||||
func sreceiver(c chan string, strobe chan bool) {
|
||||
if <-c != "hello" {
|
||||
panic("s value")
|
||||
}
|
||||
strobe <- true
|
||||
}
|
||||
|
||||
func ssender(c chan string, strobe chan bool) {
|
||||
c <- "hello again"
|
||||
strobe <- true
|
||||
}
|
||||
|
||||
var ticker = time.Tick(10 * 1000) // 10 us
|
||||
func sleep() {
|
||||
<-ticker
|
||||
<-ticker
|
||||
runtime.Gosched()
|
||||
runtime.Gosched()
|
||||
runtime.Gosched()
|
||||
}
|
||||
|
||||
const maxTries = 10000 // Up to 100ms per test.
|
||||
|
||||
func main() {
|
||||
var i32 int32
|
||||
var i64 int64
|
||||
var b bool
|
||||
var s string
|
||||
|
||||
var sync = make(chan bool)
|
||||
|
||||
for buffer := 0; buffer < 2; buffer++ {
|
||||
c32 := make(chan int32, buffer)
|
||||
c64 := make(chan int64, buffer)
|
||||
cb := make(chan bool, buffer)
|
||||
cs := make(chan string, buffer)
|
||||
|
||||
select {
|
||||
case i32 = <-c32:
|
||||
panic("blocked i32sender")
|
||||
default:
|
||||
}
|
||||
|
||||
select {
|
||||
case i64 = <-c64:
|
||||
panic("blocked i64sender")
|
||||
default:
|
||||
}
|
||||
|
||||
select {
|
||||
case b = <-cb:
|
||||
panic("blocked bsender")
|
||||
default:
|
||||
}
|
||||
|
||||
select {
|
||||
case s = <-cs:
|
||||
panic("blocked ssender")
|
||||
default:
|
||||
}
|
||||
|
||||
go i32receiver(c32, sync)
|
||||
try := 0
|
||||
Send32:
|
||||
for {
|
||||
select {
|
||||
case c32 <- 123:
|
||||
break Send32
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
println("i32receiver buffer=", buffer)
|
||||
panic("fail")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
}
|
||||
<-sync
|
||||
|
||||
go i32sender(c32, sync)
|
||||
if buffer > 0 {
|
||||
<-sync
|
||||
}
|
||||
try = 0
|
||||
Recv32:
|
||||
for {
|
||||
select {
|
||||
case i32 = <-c32:
|
||||
break Recv32
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
println("i32sender buffer=", buffer)
|
||||
panic("fail")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
}
|
||||
if i32 != 234 {
|
||||
panic("i32sender value")
|
||||
}
|
||||
if buffer == 0 {
|
||||
<-sync
|
||||
}
|
||||
|
||||
go i64receiver(c64, sync)
|
||||
try = 0
|
||||
Send64:
|
||||
for {
|
||||
select {
|
||||
case c64 <- 123456:
|
||||
break Send64
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("i64receiver")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
}
|
||||
<-sync
|
||||
|
||||
go i64sender(c64, sync)
|
||||
if buffer > 0 {
|
||||
<-sync
|
||||
}
|
||||
try = 0
|
||||
Recv64:
|
||||
for {
|
||||
select {
|
||||
case i64 = <-c64:
|
||||
break Recv64
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("i64sender")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
}
|
||||
if i64 != 234567 {
|
||||
panic("i64sender value")
|
||||
}
|
||||
if buffer == 0 {
|
||||
<-sync
|
||||
}
|
||||
|
||||
go breceiver(cb, sync)
|
||||
try = 0
|
||||
SendBool:
|
||||
for {
|
||||
select {
|
||||
case cb <- true:
|
||||
break SendBool
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("breceiver")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
}
|
||||
<-sync
|
||||
|
||||
go bsender(cb, sync)
|
||||
if buffer > 0 {
|
||||
<-sync
|
||||
}
|
||||
try = 0
|
||||
RecvBool:
|
||||
for {
|
||||
select {
|
||||
case b = <-cb:
|
||||
break RecvBool
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("bsender")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
}
|
||||
if !b {
|
||||
panic("bsender value")
|
||||
}
|
||||
if buffer == 0 {
|
||||
<-sync
|
||||
}
|
||||
|
||||
go sreceiver(cs, sync)
|
||||
try = 0
|
||||
SendString:
|
||||
for {
|
||||
select {
|
||||
case cs <- "hello":
|
||||
break SendString
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("sreceiver")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
}
|
||||
<-sync
|
||||
|
||||
go ssender(cs, sync)
|
||||
if buffer > 0 {
|
||||
<-sync
|
||||
}
|
||||
try = 0
|
||||
RecvString:
|
||||
for {
|
||||
select {
|
||||
case s = <-cs:
|
||||
break RecvString
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("ssender")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
}
|
||||
if s != "hello again" {
|
||||
panic("ssender value")
|
||||
}
|
||||
if buffer == 0 {
|
||||
<-sync
|
||||
}
|
||||
}
|
||||
}
|
||||
70
test/chan/perm.go
Normal file
70
test/chan/perm.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// errorcheck
|
||||
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Test various correct and incorrect permutations of send-only,
|
||||
// receive-only, and bidirectional channels.
|
||||
// Does not compile.
|
||||
|
||||
package main
|
||||
|
||||
var (
|
||||
cr <-chan int
|
||||
cs chan<- int
|
||||
c chan int
|
||||
)
|
||||
|
||||
func main() {
|
||||
cr = c // ok
|
||||
cs = c // ok
|
||||
c = cr // ERROR "illegal types|incompatible|cannot"
|
||||
c = cs // ERROR "illegal types|incompatible|cannot"
|
||||
cr = cs // ERROR "illegal types|incompatible|cannot"
|
||||
cs = cr // ERROR "illegal types|incompatible|cannot"
|
||||
|
||||
var n int
|
||||
<-n // ERROR "receive from non-chan|expected channel"
|
||||
n <- 2 // ERROR "send to non-chan|must be channel"
|
||||
|
||||
c <- 0 // ok
|
||||
<-c // ok
|
||||
x, ok := <-c // ok
|
||||
_, _ = x, ok
|
||||
|
||||
cr <- 0 // ERROR "send"
|
||||
<-cr // ok
|
||||
x, ok = <-cr // ok
|
||||
_, _ = x, ok
|
||||
|
||||
cs <- 0 // ok
|
||||
<-cs // ERROR "receive"
|
||||
x, ok = <-cs // ERROR "receive"
|
||||
_, _ = x, ok
|
||||
|
||||
select {
|
||||
case c <- 0: // ok
|
||||
case x := <-c: // ok
|
||||
_ = x
|
||||
|
||||
case cr <- 0: // ERROR "send"
|
||||
case x := <-cr: // ok
|
||||
_ = x
|
||||
|
||||
case cs <- 0: // ok
|
||||
case x := <-cs: // ERROR "receive"
|
||||
_ = x
|
||||
}
|
||||
|
||||
for _ = range cs { // ERROR "receive"
|
||||
}
|
||||
|
||||
for range cs { // ERROR "receive"
|
||||
}
|
||||
|
||||
close(c)
|
||||
close(cs)
|
||||
close(cr) // ERROR "receive"
|
||||
close(n) // ERROR "invalid operation.*non-chan type|must be channel|non-channel"
|
||||
}
|
||||
741
test/chan/powser1.go
Normal file
741
test/chan/powser1.go
Normal file
@@ -0,0 +1,741 @@
|
||||
// run
|
||||
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Test concurrency primitives: power series.
|
||||
|
||||
// Power series package
|
||||
// A power series is a channel, along which flow rational
|
||||
// coefficients. A denominator of zero signifies the end.
|
||||
// Original code in Newsqueak by Doug McIlroy.
|
||||
// See Squinting at Power Series by Doug McIlroy,
|
||||
// https://swtch.com/~rsc/thread/squint.pdf
|
||||
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
type rat struct {
|
||||
num, den int64 // numerator, denominator
|
||||
}
|
||||
|
||||
func (u rat) pr() {
|
||||
if u.den == 1 {
|
||||
print(u.num)
|
||||
} else {
|
||||
print(u.num, "/", u.den)
|
||||
}
|
||||
print(" ")
|
||||
}
|
||||
|
||||
func (u rat) eq(c rat) bool {
|
||||
return u.num == c.num && u.den == c.den
|
||||
}
|
||||
|
||||
type dch struct {
|
||||
req chan int
|
||||
dat chan rat
|
||||
nam int
|
||||
}
|
||||
|
||||
type dch2 [2]*dch
|
||||
|
||||
var chnames string
|
||||
var chnameserial int
|
||||
var seqno int
|
||||
|
||||
func mkdch() *dch {
|
||||
c := chnameserial % len(chnames)
|
||||
chnameserial++
|
||||
d := new(dch)
|
||||
d.req = make(chan int)
|
||||
d.dat = make(chan rat)
|
||||
d.nam = c
|
||||
return d
|
||||
}
|
||||
|
||||
func mkdch2() *dch2 {
|
||||
d2 := new(dch2)
|
||||
d2[0] = mkdch()
|
||||
d2[1] = mkdch()
|
||||
return d2
|
||||
}
|
||||
|
||||
// split reads a single demand channel and replicates its
|
||||
// output onto two, which may be read at different rates.
|
||||
// A process is created at first demand for a rat and dies
|
||||
// after the rat has been sent to both outputs.
|
||||
|
||||
// When multiple generations of split exist, the newest
|
||||
// will service requests on one channel, which is
|
||||
// always renamed to be out[0]; the oldest will service
|
||||
// requests on the other channel, out[1]. All generations but the
|
||||
// newest hold queued data that has already been sent to
|
||||
// out[0]. When data has finally been sent to out[1],
|
||||
// a signal on the release-wait channel tells the next newer
|
||||
// generation to begin servicing out[1].
|
||||
|
||||
func dosplit(in *dch, out *dch2, wait chan int) {
|
||||
both := false // do not service both channels
|
||||
|
||||
select {
|
||||
case <-out[0].req:
|
||||
|
||||
case <-wait:
|
||||
both = true
|
||||
select {
|
||||
case <-out[0].req:
|
||||
|
||||
case <-out[1].req:
|
||||
out[0], out[1] = out[1], out[0]
|
||||
}
|
||||
}
|
||||
|
||||
seqno++
|
||||
in.req <- seqno
|
||||
release := make(chan int)
|
||||
go dosplit(in, out, release)
|
||||
dat := <-in.dat
|
||||
out[0].dat <- dat
|
||||
if !both {
|
||||
<-wait
|
||||
}
|
||||
<-out[1].req
|
||||
out[1].dat <- dat
|
||||
release <- 0
|
||||
}
|
||||
|
||||
func split(in *dch, out *dch2) {
|
||||
release := make(chan int)
|
||||
go dosplit(in, out, release)
|
||||
release <- 0
|
||||
}
|
||||
|
||||
func put(dat rat, out *dch) {
|
||||
<-out.req
|
||||
out.dat <- dat
|
||||
}
|
||||
|
||||
func get(in *dch) rat {
|
||||
seqno++
|
||||
in.req <- seqno
|
||||
return <-in.dat
|
||||
}
|
||||
|
||||
// Get one rat from each of n demand channels
|
||||
|
||||
func getn(in []*dch) []rat {
|
||||
n := len(in)
|
||||
if n != 2 {
|
||||
panic("bad n in getn")
|
||||
}
|
||||
req := new([2]chan int)
|
||||
dat := new([2]chan rat)
|
||||
out := make([]rat, 2)
|
||||
var i int
|
||||
var it rat
|
||||
for i = 0; i < n; i++ {
|
||||
req[i] = in[i].req
|
||||
dat[i] = nil
|
||||
}
|
||||
for n = 2 * n; n > 0; n-- {
|
||||
seqno++
|
||||
|
||||
select {
|
||||
case req[0] <- seqno:
|
||||
dat[0] = in[0].dat
|
||||
req[0] = nil
|
||||
case req[1] <- seqno:
|
||||
dat[1] = in[1].dat
|
||||
req[1] = nil
|
||||
case it = <-dat[0]:
|
||||
out[0] = it
|
||||
dat[0] = nil
|
||||
case it = <-dat[1]:
|
||||
out[1] = it
|
||||
dat[1] = nil
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Get one rat from each of 2 demand channels
|
||||
|
||||
func get2(in0 *dch, in1 *dch) []rat {
|
||||
return getn([]*dch{in0, in1})
|
||||
}
|
||||
|
||||
func copy(in *dch, out *dch) {
|
||||
for {
|
||||
<-out.req
|
||||
out.dat <- get(in)
|
||||
}
|
||||
}
|
||||
|
||||
func repeat(dat rat, out *dch) {
|
||||
for {
|
||||
put(dat, out)
|
||||
}
|
||||
}
|
||||
|
||||
type PS *dch // power series
|
||||
type PS2 *[2]PS // pair of power series
|
||||
|
||||
var Ones PS
|
||||
var Twos PS
|
||||
|
||||
func mkPS() *dch {
|
||||
return mkdch()
|
||||
}
|
||||
|
||||
func mkPS2() *dch2 {
|
||||
return mkdch2()
|
||||
}
|
||||
|
||||
// Conventions
|
||||
// Upper-case for power series.
|
||||
// Lower-case for rationals.
|
||||
// Input variables: U,V,...
|
||||
// Output variables: ...,Y,Z
|
||||
|
||||
// Integer gcd; needed for rational arithmetic
|
||||
|
||||
func gcd(u, v int64) int64 {
|
||||
if u < 0 {
|
||||
return gcd(-u, v)
|
||||
}
|
||||
if u == 0 {
|
||||
return v
|
||||
}
|
||||
return gcd(v%u, u)
|
||||
}
|
||||
|
||||
// Make a rational from two ints and from one int
|
||||
|
||||
func i2tor(u, v int64) rat {
|
||||
g := gcd(u, v)
|
||||
var r rat
|
||||
if v > 0 {
|
||||
r.num = u / g
|
||||
r.den = v / g
|
||||
} else {
|
||||
r.num = -u / g
|
||||
r.den = -v / g
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func itor(u int64) rat {
|
||||
return i2tor(u, 1)
|
||||
}
|
||||
|
||||
var zero rat
|
||||
var one rat
|
||||
|
||||
// End mark and end test
|
||||
|
||||
var finis rat
|
||||
|
||||
func end(u rat) int64 {
|
||||
if u.den == 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Operations on rationals
|
||||
|
||||
func add(u, v rat) rat {
|
||||
g := gcd(u.den, v.den)
|
||||
return i2tor(u.num*(v.den/g)+v.num*(u.den/g), u.den*(v.den/g))
|
||||
}
|
||||
|
||||
func mul(u, v rat) rat {
|
||||
g1 := gcd(u.num, v.den)
|
||||
g2 := gcd(u.den, v.num)
|
||||
var r rat
|
||||
r.num = (u.num / g1) * (v.num / g2)
|
||||
r.den = (u.den / g2) * (v.den / g1)
|
||||
return r
|
||||
}
|
||||
|
||||
func neg(u rat) rat {
|
||||
return i2tor(-u.num, u.den)
|
||||
}
|
||||
|
||||
func sub(u, v rat) rat {
|
||||
return add(u, neg(v))
|
||||
}
|
||||
|
||||
func inv(u rat) rat { // invert a rat
|
||||
if u.num == 0 {
|
||||
panic("zero divide in inv")
|
||||
}
|
||||
return i2tor(u.den, u.num)
|
||||
}
|
||||
|
||||
// print eval in floating point of PS at x=c to n terms
|
||||
func evaln(c rat, U PS, n int) {
|
||||
xn := float64(1)
|
||||
x := float64(c.num) / float64(c.den)
|
||||
val := float64(0)
|
||||
for i := 0; i < n; i++ {
|
||||
u := get(U)
|
||||
if end(u) != 0 {
|
||||
break
|
||||
}
|
||||
val = val + x*float64(u.num)/float64(u.den)
|
||||
xn = xn * x
|
||||
}
|
||||
print(val, "\n")
|
||||
}
|
||||
|
||||
// Print n terms of a power series
|
||||
func printn(U PS, n int) {
|
||||
done := false
|
||||
for ; !done && n > 0; n-- {
|
||||
u := get(U)
|
||||
if end(u) != 0 {
|
||||
done = true
|
||||
} else {
|
||||
u.pr()
|
||||
}
|
||||
}
|
||||
print(("\n"))
|
||||
}
|
||||
|
||||
// Evaluate n terms of power series U at x=c
|
||||
func eval(c rat, U PS, n int) rat {
|
||||
if n == 0 {
|
||||
return zero
|
||||
}
|
||||
y := get(U)
|
||||
if end(y) != 0 {
|
||||
return zero
|
||||
}
|
||||
return add(y, mul(c, eval(c, U, n-1)))
|
||||
}
|
||||
|
||||
// Power-series constructors return channels on which power
|
||||
// series flow. They start an encapsulated generator that
|
||||
// puts the terms of the series on the channel.
|
||||
|
||||
// Make a pair of power series identical to a given power series
|
||||
|
||||
func Split(U PS) *dch2 {
|
||||
UU := mkdch2()
|
||||
go split(U, UU)
|
||||
return UU
|
||||
}
|
||||
|
||||
// Add two power series
|
||||
func Add(U, V PS) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
var uv []rat
|
||||
for {
|
||||
<-Z.req
|
||||
uv = get2(U, V)
|
||||
switch end(uv[0]) + 2*end(uv[1]) {
|
||||
case 0:
|
||||
Z.dat <- add(uv[0], uv[1])
|
||||
case 1:
|
||||
Z.dat <- uv[1]
|
||||
copy(V, Z)
|
||||
case 2:
|
||||
Z.dat <- uv[0]
|
||||
copy(U, Z)
|
||||
case 3:
|
||||
Z.dat <- finis
|
||||
}
|
||||
}
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
// Multiply a power series by a constant
|
||||
func Cmul(c rat, U PS) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
done := false
|
||||
for !done {
|
||||
<-Z.req
|
||||
u := get(U)
|
||||
if end(u) != 0 {
|
||||
done = true
|
||||
} else {
|
||||
Z.dat <- mul(c, u)
|
||||
}
|
||||
}
|
||||
Z.dat <- finis
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
// Subtract
|
||||
|
||||
func Sub(U, V PS) PS {
|
||||
return Add(U, Cmul(neg(one), V))
|
||||
}
|
||||
|
||||
// Multiply a power series by the monomial x^n
|
||||
|
||||
func Monmul(U PS, n int) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
for ; n > 0; n-- {
|
||||
put(zero, Z)
|
||||
}
|
||||
copy(U, Z)
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
// Multiply by x
|
||||
|
||||
func Xmul(U PS) PS {
|
||||
return Monmul(U, 1)
|
||||
}
|
||||
|
||||
func Rep(c rat) PS {
|
||||
Z := mkPS()
|
||||
go repeat(c, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Monomial c*x^n
|
||||
|
||||
func Mon(c rat, n int) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
if c.num != 0 {
|
||||
for ; n > 0; n = n - 1 {
|
||||
put(zero, Z)
|
||||
}
|
||||
put(c, Z)
|
||||
}
|
||||
put(finis, Z)
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
func Shift(c rat, U PS) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
put(c, Z)
|
||||
copy(U, Z)
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
|
||||
|
||||
// Convert array of coefficients, constant term first
|
||||
// to a (finite) power series
|
||||
|
||||
/*
|
||||
func Poly(a []rat) PS {
|
||||
Z:=mkPS()
|
||||
begin func(a []rat, Z PS) {
|
||||
j:=0
|
||||
done:=0
|
||||
for j=len(a); !done&&j>0; j=j-1)
|
||||
if(a[j-1].num!=0) done=1
|
||||
i:=0
|
||||
for(; i<j; i=i+1) put(a[i],Z)
|
||||
put(finis,Z)
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
*/
|
||||
|
||||
// Multiply. The algorithm is
|
||||
// let U = u + x*UU
|
||||
// let V = v + x*VV
|
||||
// then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
|
||||
|
||||
func Mul(U, V PS) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
<-Z.req
|
||||
uv := get2(U, V)
|
||||
if end(uv[0]) != 0 || end(uv[1]) != 0 {
|
||||
Z.dat <- finis
|
||||
} else {
|
||||
Z.dat <- mul(uv[0], uv[1])
|
||||
UU := Split(U)
|
||||
VV := Split(V)
|
||||
W := Add(Cmul(uv[0], VV[0]), Cmul(uv[1], UU[0]))
|
||||
<-Z.req
|
||||
Z.dat <- get(W)
|
||||
copy(Add(W, Mul(UU[1], VV[1])), Z)
|
||||
}
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
// Differentiate
|
||||
|
||||
func Diff(U PS) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
<-Z.req
|
||||
u := get(U)
|
||||
if end(u) == 0 {
|
||||
done := false
|
||||
for i := 1; !done; i++ {
|
||||
u = get(U)
|
||||
if end(u) != 0 {
|
||||
done = true
|
||||
} else {
|
||||
Z.dat <- mul(itor(int64(i)), u)
|
||||
<-Z.req
|
||||
}
|
||||
}
|
||||
}
|
||||
Z.dat <- finis
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
// Integrate, with const of integration
|
||||
func Integ(c rat, U PS) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
put(c, Z)
|
||||
done := false
|
||||
for i := 1; !done; i++ {
|
||||
<-Z.req
|
||||
u := get(U)
|
||||
if end(u) != 0 {
|
||||
done = true
|
||||
}
|
||||
Z.dat <- mul(i2tor(1, int64(i)), u)
|
||||
}
|
||||
Z.dat <- finis
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
// Binomial theorem (1+x)^c
|
||||
|
||||
func Binom(c rat) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
n := 1
|
||||
t := itor(1)
|
||||
for c.num != 0 {
|
||||
put(t, Z)
|
||||
t = mul(mul(t, c), i2tor(1, int64(n)))
|
||||
c = sub(c, one)
|
||||
n++
|
||||
}
|
||||
put(finis, Z)
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
// Reciprocal of a power series
|
||||
// let U = u + x*UU
|
||||
// let Z = z + x*ZZ
|
||||
// (u+x*UU)*(z+x*ZZ) = 1
|
||||
// z = 1/u
|
||||
// u*ZZ + z*UU +x*UU*ZZ = 0
|
||||
// ZZ = -UU*(z+x*ZZ)/u
|
||||
|
||||
func Recip(U PS) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
ZZ := mkPS2()
|
||||
<-Z.req
|
||||
z := inv(get(U))
|
||||
Z.dat <- z
|
||||
split(Mul(Cmul(neg(z), U), Shift(z, ZZ[0])), ZZ)
|
||||
copy(ZZ[1], Z)
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
// Exponential of a power series with constant term 0
|
||||
// (nonzero constant term would make nonrational coefficients)
|
||||
// bug: the constant term is simply ignored
|
||||
// Z = exp(U)
|
||||
// DZ = Z*DU
|
||||
// integrate to get Z
|
||||
|
||||
func Exp(U PS) PS {
|
||||
ZZ := mkPS2()
|
||||
split(Integ(one, Mul(ZZ[0], Diff(U))), ZZ)
|
||||
return ZZ[1]
|
||||
}
|
||||
|
||||
// Substitute V for x in U, where the leading term of V is zero
|
||||
// let U = u + x*UU
|
||||
// let V = v + x*VV
|
||||
// then S(U,V) = u + VV*S(V,UU)
|
||||
// bug: a nonzero constant term is ignored
|
||||
|
||||
func Subst(U, V PS) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
VV := Split(V)
|
||||
<-Z.req
|
||||
u := get(U)
|
||||
Z.dat <- u
|
||||
if end(u) == 0 {
|
||||
if end(get(VV[0])) != 0 {
|
||||
put(finis, Z)
|
||||
} else {
|
||||
copy(Mul(VV[0], Subst(U, VV[1])), Z)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
// Monomial Substitution: U(c x^n)
|
||||
// Each Ui is multiplied by c^i and followed by n-1 zeros
|
||||
|
||||
func MonSubst(U PS, c0 rat, n int) PS {
|
||||
Z := mkPS()
|
||||
go func() {
|
||||
c := one
|
||||
for {
|
||||
<-Z.req
|
||||
u := get(U)
|
||||
Z.dat <- mul(u, c)
|
||||
c = mul(c, c0)
|
||||
if end(u) != 0 {
|
||||
Z.dat <- finis
|
||||
break
|
||||
}
|
||||
for i := 1; i < n; i++ {
|
||||
<-Z.req
|
||||
Z.dat <- zero
|
||||
}
|
||||
}
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
|
||||
func Init() {
|
||||
chnameserial = -1
|
||||
seqno = 0
|
||||
chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
zero = itor(0)
|
||||
one = itor(1)
|
||||
finis = i2tor(1, 0)
|
||||
Ones = Rep(one)
|
||||
Twos = Rep(itor(2))
|
||||
}
|
||||
|
||||
func check(U PS, c rat, count int, str string) {
|
||||
for i := 0; i < count; i++ {
|
||||
r := get(U)
|
||||
if !r.eq(c) {
|
||||
print("got: ")
|
||||
r.pr()
|
||||
print("should get ")
|
||||
c.pr()
|
||||
print("\n")
|
||||
panic(str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const N = 10
|
||||
|
||||
func checka(U PS, a []rat, str string) {
|
||||
for i := 0; i < N; i++ {
|
||||
check(U, a[i], 1, str)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
Init()
|
||||
if len(os.Args) > 1 { // print
|
||||
print("Ones: ")
|
||||
printn(Ones, 10)
|
||||
print("Twos: ")
|
||||
printn(Twos, 10)
|
||||
print("Add: ")
|
||||
printn(Add(Ones, Twos), 10)
|
||||
print("Diff: ")
|
||||
printn(Diff(Ones), 10)
|
||||
print("Integ: ")
|
||||
printn(Integ(zero, Ones), 10)
|
||||
print("CMul: ")
|
||||
printn(Cmul(neg(one), Ones), 10)
|
||||
print("Sub: ")
|
||||
printn(Sub(Ones, Twos), 10)
|
||||
print("Mul: ")
|
||||
printn(Mul(Ones, Ones), 10)
|
||||
print("Exp: ")
|
||||
printn(Exp(Ones), 15)
|
||||
print("MonSubst: ")
|
||||
printn(MonSubst(Ones, neg(one), 2), 10)
|
||||
print("ATan: ")
|
||||
printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
|
||||
} else { // test
|
||||
check(Ones, one, 5, "Ones")
|
||||
check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones") // 1 1 1 1 1
|
||||
check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos") // 3 3 3 3 3
|
||||
a := make([]rat, N)
|
||||
d := Diff(Ones)
|
||||
for i := 0; i < N; i++ {
|
||||
a[i] = itor(int64(i + 1))
|
||||
}
|
||||
checka(d, a, "Diff") // 1 2 3 4 5
|
||||
in := Integ(zero, Ones)
|
||||
a[0] = zero // integration constant
|
||||
for i := 1; i < N; i++ {
|
||||
a[i] = i2tor(1, int64(i))
|
||||
}
|
||||
checka(in, a, "Integ") // 0 1 1/2 1/3 1/4 1/5
|
||||
check(Cmul(neg(one), Twos), itor(-2), 10, "CMul") // -1 -1 -1 -1 -1
|
||||
check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos") // -1 -1 -1 -1 -1
|
||||
m := Mul(Ones, Ones)
|
||||
for i := 0; i < N; i++ {
|
||||
a[i] = itor(int64(i + 1))
|
||||
}
|
||||
checka(m, a, "Mul") // 1 2 3 4 5
|
||||
e := Exp(Ones)
|
||||
a[0] = itor(1)
|
||||
a[1] = itor(1)
|
||||
a[2] = i2tor(3, 2)
|
||||
a[3] = i2tor(13, 6)
|
||||
a[4] = i2tor(73, 24)
|
||||
a[5] = i2tor(167, 40)
|
||||
a[6] = i2tor(4051, 720)
|
||||
a[7] = i2tor(37633, 5040)
|
||||
a[8] = i2tor(43817, 4480)
|
||||
a[9] = i2tor(4596553, 362880)
|
||||
checka(e, a, "Exp") // 1 1 3/2 13/6 73/24
|
||||
at := Integ(zero, MonSubst(Ones, neg(one), 2))
|
||||
for c, i := 1, 0; i < N; i++ {
|
||||
if i%2 == 0 {
|
||||
a[i] = zero
|
||||
} else {
|
||||
a[i] = i2tor(int64(c), int64(i))
|
||||
c *= -1
|
||||
}
|
||||
}
|
||||
checka(at, a, "ATan") // 0 -1 0 -1/3 0 -1/5
|
||||
/*
|
||||
t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
|
||||
a[0] = zero
|
||||
a[1] = itor(1)
|
||||
a[2] = zero
|
||||
a[3] = i2tor(1,3)
|
||||
a[4] = zero
|
||||
a[5] = i2tor(2,15)
|
||||
a[6] = zero
|
||||
a[7] = i2tor(17,315)
|
||||
a[8] = zero
|
||||
a[9] = i2tor(62,2835)
|
||||
checka(t, a, "Tan") // 0 1 0 1/3 0 2/15
|
||||
*/
|
||||
}
|
||||
}
|
||||
755
test/chan/powser2.go
Normal file
755
test/chan/powser2.go
Normal file
@@ -0,0 +1,755 @@
|
||||
// run
|
||||
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Test concurrency primitives: power series.
|
||||
|
||||
// Like powser1.go but uses channels of interfaces.
|
||||
// Has not been cleaned up as much as powser1.go, to keep
|
||||
// it distinct and therefore a different test.
|
||||
|
||||
// Power series package
|
||||
// A power series is a channel, along which flow rational
|
||||
// coefficients. A denominator of zero signifies the end.
|
||||
// Original code in Newsqueak by Doug McIlroy.
|
||||
// See Squinting at Power Series by Doug McIlroy,
|
||||
// https://swtch.com/~rsc/thread/squint.pdf
|
||||
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
type rat struct {
|
||||
num, den int64 // numerator, denominator
|
||||
}
|
||||
|
||||
type item interface {
|
||||
pr()
|
||||
eq(c item) bool
|
||||
}
|
||||
|
||||
func (u *rat) pr() {
|
||||
if u.den == 1 {
|
||||
print(u.num)
|
||||
} else {
|
||||
print(u.num, "/", u.den)
|
||||
}
|
||||
print(" ")
|
||||
}
|
||||
|
||||
func (u *rat) eq(c item) bool {
|
||||
c1 := c.(*rat)
|
||||
return u.num == c1.num && u.den == c1.den
|
||||
}
|
||||
|
||||
type dch struct {
|
||||
req chan int
|
||||
dat chan item
|
||||
nam int
|
||||
}
|
||||
|
||||
type dch2 [2]*dch
|
||||
|
||||
var chnames string
|
||||
var chnameserial int
|
||||
var seqno int
|
||||
|
||||
func mkdch() *dch {
|
||||
c := chnameserial % len(chnames)
|
||||
chnameserial++
|
||||
d := new(dch)
|
||||
d.req = make(chan int)
|
||||
d.dat = make(chan item)
|
||||
d.nam = c
|
||||
return d
|
||||
}
|
||||
|
||||
func mkdch2() *dch2 {
|
||||
d2 := new(dch2)
|
||||
d2[0] = mkdch()
|
||||
d2[1] = mkdch()
|
||||
return d2
|
||||
}
|
||||
|
||||
// split reads a single demand channel and replicates its
|
||||
// output onto two, which may be read at different rates.
|
||||
// A process is created at first demand for an item and dies
|
||||
// after the item has been sent to both outputs.
|
||||
|
||||
// When multiple generations of split exist, the newest
|
||||
// will service requests on one channel, which is
|
||||
// always renamed to be out[0]; the oldest will service
|
||||
// requests on the other channel, out[1]. All generations but the
|
||||
// newest hold queued data that has already been sent to
|
||||
// out[0]. When data has finally been sent to out[1],
|
||||
// a signal on the release-wait channel tells the next newer
|
||||
// generation to begin servicing out[1].
|
||||
|
||||
func dosplit(in *dch, out *dch2, wait chan int) {
|
||||
both := false // do not service both channels
|
||||
|
||||
select {
|
||||
case <-out[0].req:
|
||||
|
||||
case <-wait:
|
||||
both = true
|
||||
select {
|
||||
case <-out[0].req:
|
||||
|
||||
case <-out[1].req:
|
||||
out[0], out[1] = out[1], out[0]
|
||||
}
|
||||
}
|
||||
|
||||
seqno++
|
||||
in.req <- seqno
|
||||
release := make(chan int)
|
||||
go dosplit(in, out, release)
|
||||
dat := <-in.dat
|
||||
out[0].dat <- dat
|
||||
if !both {
|
||||
<-wait
|
||||
}
|
||||
<-out[1].req
|
||||
out[1].dat <- dat
|
||||
release <- 0
|
||||
}
|
||||
|
||||
func split(in *dch, out *dch2) {
|
||||
release := make(chan int)
|
||||
go dosplit(in, out, release)
|
||||
release <- 0
|
||||
}
|
||||
|
||||
func put(dat item, out *dch) {
|
||||
<-out.req
|
||||
out.dat <- dat
|
||||
}
|
||||
|
||||
func get(in *dch) *rat {
|
||||
seqno++
|
||||
in.req <- seqno
|
||||
return (<-in.dat).(*rat)
|
||||
}
|
||||
|
||||
// Get one item from each of n demand channels
|
||||
|
||||
func getn(in []*dch) []item {
|
||||
n := len(in)
|
||||
if n != 2 {
|
||||
panic("bad n in getn")
|
||||
}
|
||||
req := make([]chan int, 2)
|
||||
dat := make([]chan item, 2)
|
||||
out := make([]item, 2)
|
||||
var i int
|
||||
var it item
|
||||
for i = 0; i < n; i++ {
|
||||
req[i] = in[i].req
|
||||
dat[i] = nil
|
||||
}
|
||||
for n = 2 * n; n > 0; n-- {
|
||||
seqno++
|
||||
|
||||
select {
|
||||
case req[0] <- seqno:
|
||||
dat[0] = in[0].dat
|
||||
req[0] = nil
|
||||
case req[1] <- seqno:
|
||||
dat[1] = in[1].dat
|
||||
req[1] = nil
|
||||
case it = <-dat[0]:
|
||||
out[0] = it
|
||||
dat[0] = nil
|
||||
case it = <-dat[1]:
|
||||
out[1] = it
|
||||
dat[1] = nil
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Get one item from each of 2 demand channels
|
||||
|
||||
func get2(in0 *dch, in1 *dch) []item {
|
||||
return getn([]*dch{in0, in1})
|
||||
}
|
||||
|
||||
func copy(in *dch, out *dch) {
|
||||
for {
|
||||
<-out.req
|
||||
out.dat <- get(in)
|
||||
}
|
||||
}
|
||||
|
||||
func repeat(dat item, out *dch) {
|
||||
for {
|
||||
put(dat, out)
|
||||
}
|
||||
}
|
||||
|
||||
type PS *dch // power series
|
||||
type PS2 *[2]PS // pair of power series
|
||||
|
||||
var Ones PS
|
||||
var Twos PS
|
||||
|
||||
func mkPS() *dch {
|
||||
return mkdch()
|
||||
}
|
||||
|
||||
func mkPS2() *dch2 {
|
||||
return mkdch2()
|
||||
}
|
||||
|
||||
// Conventions
|
||||
// Upper-case for power series.
|
||||
// Lower-case for rationals.
|
||||
// Input variables: U,V,...
|
||||
// Output variables: ...,Y,Z
|
||||
|
||||
// Integer gcd; needed for rational arithmetic
|
||||
|
||||
func gcd(u, v int64) int64 {
|
||||
if u < 0 {
|
||||
return gcd(-u, v)
|
||||
}
|
||||
if u == 0 {
|
||||
return v
|
||||
}
|
||||
return gcd(v%u, u)
|
||||
}
|
||||
|
||||
// Make a rational from two ints and from one int
|
||||
|
||||
func i2tor(u, v int64) *rat {
|
||||
g := gcd(u, v)
|
||||
r := new(rat)
|
||||
if v > 0 {
|
||||
r.num = u / g
|
||||
r.den = v / g
|
||||
} else {
|
||||
r.num = -u / g
|
||||
r.den = -v / g
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func itor(u int64) *rat {
|
||||
return i2tor(u, 1)
|
||||
}
|
||||
|
||||
var zero *rat
|
||||
var one *rat
|
||||
|
||||
// End mark and end test
|
||||
|
||||
var finis *rat
|
||||
|
||||
func end(u *rat) int64 {
|
||||
if u.den == 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Operations on rationals
|
||||
|
||||
func add(u, v *rat) *rat {
|
||||
g := gcd(u.den, v.den)
|
||||
return i2tor(u.num*(v.den/g)+v.num*(u.den/g), u.den*(v.den/g))
|
||||
}
|
||||
|
||||
func mul(u, v *rat) *rat {
|
||||
g1 := gcd(u.num, v.den)
|
||||
g2 := gcd(u.den, v.num)
|
||||
r := new(rat)
|
||||
r.num = (u.num / g1) * (v.num / g2)
|
||||
r.den = (u.den / g2) * (v.den / g1)
|
||||
return r
|
||||
}
|
||||
|
||||
func neg(u *rat) *rat {
|
||||
return i2tor(-u.num, u.den)
|
||||
}
|
||||
|
||||
func sub(u, v *rat) *rat {
|
||||
return add(u, neg(v))
|
||||
}
|
||||
|
||||
func inv(u *rat) *rat { // invert a rat
|
||||
if u.num == 0 {
|
||||
panic("zero divide in inv")
|
||||
}
|
||||
return i2tor(u.den, u.num)
|
||||
}
|
||||
|
||||
// print eval in floating point of PS at x=c to n terms
|
||||
func Evaln(c *rat, U PS, n int) {
|
||||
xn := float64(1)
|
||||
x := float64(c.num) / float64(c.den)
|
||||
val := float64(0)
|
||||
for i := 0; i < n; i++ {
|
||||
u := get(U)
|
||||
if end(u) != 0 {
|
||||
break
|
||||
}
|
||||
val = val + x*float64(u.num)/float64(u.den)
|
||||
xn = xn * x
|
||||
}
|
||||
print(val, "\n")
|
||||
}
|
||||
|
||||
// Print n terms of a power series
|
||||
func Printn(U PS, n int) {
|
||||
done := false
|
||||
for ; !done && n > 0; n-- {
|
||||
u := get(U)
|
||||
if end(u) != 0 {
|
||||
done = true
|
||||
} else {
|
||||
u.pr()
|
||||
}
|
||||
}
|
||||
print(("\n"))
|
||||
}
|
||||
|
||||
func Print(U PS) {
|
||||
Printn(U, 1000000000)
|
||||
}
|
||||
|
||||
// Evaluate n terms of power series U at x=c
|
||||
func eval(c *rat, U PS, n int) *rat {
|
||||
if n == 0 {
|
||||
return zero
|
||||
}
|
||||
y := get(U)
|
||||
if end(y) != 0 {
|
||||
return zero
|
||||
}
|
||||
return add(y, mul(c, eval(c, U, n-1)))
|
||||
}
|
||||
|
||||
// Power-series constructors return channels on which power
|
||||
// series flow. They start an encapsulated generator that
|
||||
// puts the terms of the series on the channel.
|
||||
|
||||
// Make a pair of power series identical to a given power series
|
||||
|
||||
func Split(U PS) *dch2 {
|
||||
UU := mkdch2()
|
||||
go split(U, UU)
|
||||
return UU
|
||||
}
|
||||
|
||||
// Add two power series
|
||||
func Add(U, V PS) PS {
|
||||
Z := mkPS()
|
||||
go func(U, V, Z PS) {
|
||||
var uv []item
|
||||
for {
|
||||
<-Z.req
|
||||
uv = get2(U, V)
|
||||
switch end(uv[0].(*rat)) + 2*end(uv[1].(*rat)) {
|
||||
case 0:
|
||||
Z.dat <- add(uv[0].(*rat), uv[1].(*rat))
|
||||
case 1:
|
||||
Z.dat <- uv[1]
|
||||
copy(V, Z)
|
||||
case 2:
|
||||
Z.dat <- uv[0]
|
||||
copy(U, Z)
|
||||
case 3:
|
||||
Z.dat <- finis
|
||||
}
|
||||
}
|
||||
}(U, V, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Multiply a power series by a constant
|
||||
func Cmul(c *rat, U PS) PS {
|
||||
Z := mkPS()
|
||||
go func(c *rat, U, Z PS) {
|
||||
done := false
|
||||
for !done {
|
||||
<-Z.req
|
||||
u := get(U)
|
||||
if end(u) != 0 {
|
||||
done = true
|
||||
} else {
|
||||
Z.dat <- mul(c, u)
|
||||
}
|
||||
}
|
||||
Z.dat <- finis
|
||||
}(c, U, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Subtract
|
||||
|
||||
func Sub(U, V PS) PS {
|
||||
return Add(U, Cmul(neg(one), V))
|
||||
}
|
||||
|
||||
// Multiply a power series by the monomial x^n
|
||||
|
||||
func Monmul(U PS, n int) PS {
|
||||
Z := mkPS()
|
||||
go func(n int, U PS, Z PS) {
|
||||
for ; n > 0; n-- {
|
||||
put(zero, Z)
|
||||
}
|
||||
copy(U, Z)
|
||||
}(n, U, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Multiply by x
|
||||
|
||||
func Xmul(U PS) PS {
|
||||
return Monmul(U, 1)
|
||||
}
|
||||
|
||||
func Rep(c *rat) PS {
|
||||
Z := mkPS()
|
||||
go repeat(c, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Monomial c*x^n
|
||||
|
||||
func Mon(c *rat, n int) PS {
|
||||
Z := mkPS()
|
||||
go func(c *rat, n int, Z PS) {
|
||||
if c.num != 0 {
|
||||
for ; n > 0; n = n - 1 {
|
||||
put(zero, Z)
|
||||
}
|
||||
put(c, Z)
|
||||
}
|
||||
put(finis, Z)
|
||||
}(c, n, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
func Shift(c *rat, U PS) PS {
|
||||
Z := mkPS()
|
||||
go func(c *rat, U, Z PS) {
|
||||
put(c, Z)
|
||||
copy(U, Z)
|
||||
}(c, U, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
|
||||
|
||||
// Convert array of coefficients, constant term first
|
||||
// to a (finite) power series
|
||||
|
||||
/*
|
||||
func Poly(a [] *rat) PS{
|
||||
Z:=mkPS()
|
||||
begin func(a [] *rat, Z PS){
|
||||
j:=0
|
||||
done:=0
|
||||
for j=len(a); !done&&j>0; j=j-1)
|
||||
if(a[j-1].num!=0) done=1
|
||||
i:=0
|
||||
for(; i<j; i=i+1) put(a[i],Z)
|
||||
put(finis,Z)
|
||||
}()
|
||||
return Z
|
||||
}
|
||||
*/
|
||||
|
||||
// Multiply. The algorithm is
|
||||
// let U = u + x*UU
|
||||
// let V = v + x*VV
|
||||
// then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
|
||||
|
||||
func Mul(U, V PS) PS {
|
||||
Z := mkPS()
|
||||
go func(U, V, Z PS) {
|
||||
<-Z.req
|
||||
uv := get2(U, V)
|
||||
if end(uv[0].(*rat)) != 0 || end(uv[1].(*rat)) != 0 {
|
||||
Z.dat <- finis
|
||||
} else {
|
||||
Z.dat <- mul(uv[0].(*rat), uv[1].(*rat))
|
||||
UU := Split(U)
|
||||
VV := Split(V)
|
||||
W := Add(Cmul(uv[0].(*rat), VV[0]), Cmul(uv[1].(*rat), UU[0]))
|
||||
<-Z.req
|
||||
Z.dat <- get(W)
|
||||
copy(Add(W, Mul(UU[1], VV[1])), Z)
|
||||
}
|
||||
}(U, V, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Differentiate
|
||||
|
||||
func Diff(U PS) PS {
|
||||
Z := mkPS()
|
||||
go func(U, Z PS) {
|
||||
<-Z.req
|
||||
u := get(U)
|
||||
if end(u) == 0 {
|
||||
done := false
|
||||
for i := 1; !done; i++ {
|
||||
u = get(U)
|
||||
if end(u) != 0 {
|
||||
done = true
|
||||
} else {
|
||||
Z.dat <- mul(itor(int64(i)), u)
|
||||
<-Z.req
|
||||
}
|
||||
}
|
||||
}
|
||||
Z.dat <- finis
|
||||
}(U, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Integrate, with const of integration
|
||||
func Integ(c *rat, U PS) PS {
|
||||
Z := mkPS()
|
||||
go func(c *rat, U, Z PS) {
|
||||
put(c, Z)
|
||||
done := false
|
||||
for i := 1; !done; i++ {
|
||||
<-Z.req
|
||||
u := get(U)
|
||||
if end(u) != 0 {
|
||||
done = true
|
||||
}
|
||||
Z.dat <- mul(i2tor(1, int64(i)), u)
|
||||
}
|
||||
Z.dat <- finis
|
||||
}(c, U, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Binomial theorem (1+x)^c
|
||||
|
||||
func Binom(c *rat) PS {
|
||||
Z := mkPS()
|
||||
go func(c *rat, Z PS) {
|
||||
n := 1
|
||||
t := itor(1)
|
||||
for c.num != 0 {
|
||||
put(t, Z)
|
||||
t = mul(mul(t, c), i2tor(1, int64(n)))
|
||||
c = sub(c, one)
|
||||
n++
|
||||
}
|
||||
put(finis, Z)
|
||||
}(c, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Reciprocal of a power series
|
||||
// let U = u + x*UU
|
||||
// let Z = z + x*ZZ
|
||||
// (u+x*UU)*(z+x*ZZ) = 1
|
||||
// z = 1/u
|
||||
// u*ZZ + z*UU +x*UU*ZZ = 0
|
||||
// ZZ = -UU*(z+x*ZZ)/u
|
||||
|
||||
func Recip(U PS) PS {
|
||||
Z := mkPS()
|
||||
go func(U, Z PS) {
|
||||
ZZ := mkPS2()
|
||||
<-Z.req
|
||||
z := inv(get(U))
|
||||
Z.dat <- z
|
||||
split(Mul(Cmul(neg(z), U), Shift(z, ZZ[0])), ZZ)
|
||||
copy(ZZ[1], Z)
|
||||
}(U, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Exponential of a power series with constant term 0
|
||||
// (nonzero constant term would make nonrational coefficients)
|
||||
// bug: the constant term is simply ignored
|
||||
// Z = exp(U)
|
||||
// DZ = Z*DU
|
||||
// integrate to get Z
|
||||
|
||||
func Exp(U PS) PS {
|
||||
ZZ := mkPS2()
|
||||
split(Integ(one, Mul(ZZ[0], Diff(U))), ZZ)
|
||||
return ZZ[1]
|
||||
}
|
||||
|
||||
// Substitute V for x in U, where the leading term of V is zero
|
||||
// let U = u + x*UU
|
||||
// let V = v + x*VV
|
||||
// then S(U,V) = u + VV*S(V,UU)
|
||||
// bug: a nonzero constant term is ignored
|
||||
|
||||
func Subst(U, V PS) PS {
|
||||
Z := mkPS()
|
||||
go func(U, V, Z PS) {
|
||||
VV := Split(V)
|
||||
<-Z.req
|
||||
u := get(U)
|
||||
Z.dat <- u
|
||||
if end(u) == 0 {
|
||||
if end(get(VV[0])) != 0 {
|
||||
put(finis, Z)
|
||||
} else {
|
||||
copy(Mul(VV[0], Subst(U, VV[1])), Z)
|
||||
}
|
||||
}
|
||||
}(U, V, Z)
|
||||
return Z
|
||||
}
|
||||
|
||||
// Monomial Substitution: U(c x^n)
|
||||
// Each Ui is multiplied by c^i and followed by n-1 zeros
|
||||
|
||||
func MonSubst(U PS, c0 *rat, n int) PS {
|
||||
Z := mkPS()
|
||||
go func(U, Z PS, c0 *rat, n int) {
|
||||
c := one
|
||||
for {
|
||||
<-Z.req
|
||||
u := get(U)
|
||||
Z.dat <- mul(u, c)
|
||||
c = mul(c, c0)
|
||||
if end(u) != 0 {
|
||||
Z.dat <- finis
|
||||
break
|
||||
}
|
||||
for i := 1; i < n; i++ {
|
||||
<-Z.req
|
||||
Z.dat <- zero
|
||||
}
|
||||
}
|
||||
}(U, Z, c0, n)
|
||||
return Z
|
||||
}
|
||||
|
||||
func Init() {
|
||||
chnameserial = -1
|
||||
seqno = 0
|
||||
chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
zero = itor(0)
|
||||
one = itor(1)
|
||||
finis = i2tor(1, 0)
|
||||
Ones = Rep(one)
|
||||
Twos = Rep(itor(2))
|
||||
}
|
||||
|
||||
func check(U PS, c *rat, count int, str string) {
|
||||
for i := 0; i < count; i++ {
|
||||
r := get(U)
|
||||
if !r.eq(c) {
|
||||
print("got: ")
|
||||
r.pr()
|
||||
print("should get ")
|
||||
c.pr()
|
||||
print("\n")
|
||||
panic(str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const N = 10
|
||||
|
||||
func checka(U PS, a []*rat, str string) {
|
||||
for i := 0; i < N; i++ {
|
||||
check(U, a[i], 1, str)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
Init()
|
||||
if len(os.Args) > 1 { // print
|
||||
print("Ones: ")
|
||||
Printn(Ones, 10)
|
||||
print("Twos: ")
|
||||
Printn(Twos, 10)
|
||||
print("Add: ")
|
||||
Printn(Add(Ones, Twos), 10)
|
||||
print("Diff: ")
|
||||
Printn(Diff(Ones), 10)
|
||||
print("Integ: ")
|
||||
Printn(Integ(zero, Ones), 10)
|
||||
print("CMul: ")
|
||||
Printn(Cmul(neg(one), Ones), 10)
|
||||
print("Sub: ")
|
||||
Printn(Sub(Ones, Twos), 10)
|
||||
print("Mul: ")
|
||||
Printn(Mul(Ones, Ones), 10)
|
||||
print("Exp: ")
|
||||
Printn(Exp(Ones), 15)
|
||||
print("MonSubst: ")
|
||||
Printn(MonSubst(Ones, neg(one), 2), 10)
|
||||
print("ATan: ")
|
||||
Printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
|
||||
} else { // test
|
||||
check(Ones, one, 5, "Ones")
|
||||
check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones") // 1 1 1 1 1
|
||||
check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos") // 3 3 3 3 3
|
||||
a := make([]*rat, N)
|
||||
d := Diff(Ones)
|
||||
for i := 0; i < N; i++ {
|
||||
a[i] = itor(int64(i + 1))
|
||||
}
|
||||
checka(d, a, "Diff") // 1 2 3 4 5
|
||||
in := Integ(zero, Ones)
|
||||
a[0] = zero // integration constant
|
||||
for i := 1; i < N; i++ {
|
||||
a[i] = i2tor(1, int64(i))
|
||||
}
|
||||
checka(in, a, "Integ") // 0 1 1/2 1/3 1/4 1/5
|
||||
check(Cmul(neg(one), Twos), itor(-2), 10, "CMul") // -1 -1 -1 -1 -1
|
||||
check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos") // -1 -1 -1 -1 -1
|
||||
m := Mul(Ones, Ones)
|
||||
for i := 0; i < N; i++ {
|
||||
a[i] = itor(int64(i + 1))
|
||||
}
|
||||
checka(m, a, "Mul") // 1 2 3 4 5
|
||||
e := Exp(Ones)
|
||||
a[0] = itor(1)
|
||||
a[1] = itor(1)
|
||||
a[2] = i2tor(3, 2)
|
||||
a[3] = i2tor(13, 6)
|
||||
a[4] = i2tor(73, 24)
|
||||
a[5] = i2tor(167, 40)
|
||||
a[6] = i2tor(4051, 720)
|
||||
a[7] = i2tor(37633, 5040)
|
||||
a[8] = i2tor(43817, 4480)
|
||||
a[9] = i2tor(4596553, 362880)
|
||||
checka(e, a, "Exp") // 1 1 3/2 13/6 73/24
|
||||
at := Integ(zero, MonSubst(Ones, neg(one), 2))
|
||||
for c, i := 1, 0; i < N; i++ {
|
||||
if i%2 == 0 {
|
||||
a[i] = zero
|
||||
} else {
|
||||
a[i] = i2tor(int64(c), int64(i))
|
||||
c *= -1
|
||||
}
|
||||
}
|
||||
checka(at, a, "ATan") // 0 -1 0 -1/3 0 -1/5
|
||||
/*
|
||||
t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
|
||||
a[0] = zero
|
||||
a[1] = itor(1)
|
||||
a[2] = zero
|
||||
a[3] = i2tor(1,3)
|
||||
a[4] = zero
|
||||
a[5] = i2tor(2,15)
|
||||
a[6] = zero
|
||||
a[7] = i2tor(17,315)
|
||||
a[8] = zero
|
||||
a[9] = i2tor(62,2835)
|
||||
checka(t, a, "Tan") // 0 1 0 1/3 0 2/15
|
||||
*/
|
||||
}
|
||||
}
|
||||
58
test/chan/select.go
Normal file
58
test/chan/select.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// run
|
||||
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Test simple select.
|
||||
|
||||
package main
|
||||
|
||||
var counter uint
|
||||
var shift uint
|
||||
|
||||
func GetValue() uint {
|
||||
counter++
|
||||
return 1 << shift
|
||||
}
|
||||
|
||||
func Send(a, b chan uint) int {
|
||||
var i int
|
||||
|
||||
LOOP:
|
||||
for {
|
||||
select {
|
||||
case a <- GetValue():
|
||||
i++
|
||||
a = nil
|
||||
case b <- GetValue():
|
||||
i++
|
||||
b = nil
|
||||
default:
|
||||
break LOOP
|
||||
}
|
||||
shift++
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := make(chan uint, 1)
|
||||
b := make(chan uint, 1)
|
||||
if v := Send(a, b); v != 2 {
|
||||
println("Send returned", v, "!= 2")
|
||||
panic("fail")
|
||||
}
|
||||
if av, bv := <-a, <-b; av|bv != 3 {
|
||||
println("bad values", av, bv)
|
||||
panic("fail")
|
||||
}
|
||||
if v := Send(a, nil); v != 1 {
|
||||
println("Send returned", v, "!= 1")
|
||||
panic("fail")
|
||||
}
|
||||
if counter != 10 {
|
||||
println("counter is", counter, "!= 10")
|
||||
panic("fail")
|
||||
}
|
||||
}
|
||||
54
test/chan/select2.go
Normal file
54
test/chan/select2.go
Normal file
@@ -0,0 +1,54 @@
|
||||
// run
|
||||
|
||||
// Copyright 2010 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.
|
||||
|
||||
// Test that selects do not consume undue memory.
|
||||
|
||||
package main
|
||||
|
||||
import "runtime"
|
||||
|
||||
func sender(c chan int, n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
c <- 1
|
||||
}
|
||||
}
|
||||
|
||||
func receiver(c, dummy chan int, n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
select {
|
||||
case <-c:
|
||||
// nothing
|
||||
case <-dummy:
|
||||
panic("dummy")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
runtime.MemProfileRate = 0
|
||||
|
||||
c := make(chan int)
|
||||
dummy := make(chan int)
|
||||
|
||||
// warm up
|
||||
go sender(c, 100000)
|
||||
receiver(c, dummy, 100000)
|
||||
runtime.GC()
|
||||
memstats := new(runtime.MemStats)
|
||||
runtime.ReadMemStats(memstats)
|
||||
alloc := memstats.Alloc
|
||||
|
||||
// second time shouldn't increase footprint by much
|
||||
go sender(c, 100000)
|
||||
receiver(c, dummy, 100000)
|
||||
runtime.GC()
|
||||
runtime.ReadMemStats(memstats)
|
||||
|
||||
// Be careful to avoid wraparound.
|
||||
if memstats.Alloc > alloc && memstats.Alloc-alloc > 1.1e5 {
|
||||
println("BUG: too much memory for 100,000 selects:", memstats.Alloc-alloc)
|
||||
}
|
||||
}
|
||||
226
test/chan/select3.go
Normal file
226
test/chan/select3.go
Normal file
@@ -0,0 +1,226 @@
|
||||
// run
|
||||
|
||||
// Copyright 2010 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.
|
||||
|
||||
// Test the semantics of the select statement
|
||||
// for basic empty/non-empty cases.
|
||||
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
const always = "function did not"
|
||||
const never = "function did"
|
||||
|
||||
func unreachable() {
|
||||
panic("control flow shouldn't reach here")
|
||||
}
|
||||
|
||||
// Calls f and verifies that f always/never panics depending on signal.
|
||||
func testPanic(signal string, f func()) {
|
||||
defer func() {
|
||||
s := never
|
||||
if recover() != nil {
|
||||
s = always // f panicked
|
||||
}
|
||||
if s != signal {
|
||||
panic(signal + " panic")
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
|
||||
// Calls f and empirically verifies that f always/never blocks depending on signal.
|
||||
func testBlock(signal string, f func()) {
|
||||
c := make(chan string)
|
||||
go func() {
|
||||
f()
|
||||
c <- never // f didn't block
|
||||
}()
|
||||
go func() {
|
||||
if signal == never {
|
||||
// Wait a long time to make sure that we don't miss our window by accident on a slow machine.
|
||||
time.Sleep(10 * time.Second)
|
||||
} else {
|
||||
// Wait as short a time as we can without false negatives.
|
||||
// 10ms should be long enough to catch most failures.
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
c <- always // f blocked always
|
||||
}()
|
||||
if <-c != signal {
|
||||
panic(signal + " block")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
const async = 1 // asynchronous channels
|
||||
var nilch chan int
|
||||
closedch := make(chan int)
|
||||
close(closedch)
|
||||
|
||||
// sending/receiving from a nil channel blocks
|
||||
testBlock(always, func() {
|
||||
nilch <- 7
|
||||
})
|
||||
testBlock(always, func() {
|
||||
<-nilch
|
||||
})
|
||||
|
||||
// sending/receiving from a nil channel inside a select is never selected
|
||||
testPanic(never, func() {
|
||||
select {
|
||||
case nilch <- 7:
|
||||
unreachable()
|
||||
default:
|
||||
}
|
||||
})
|
||||
testPanic(never, func() {
|
||||
select {
|
||||
case <-nilch:
|
||||
unreachable()
|
||||
default:
|
||||
}
|
||||
})
|
||||
|
||||
// sending to an async channel with free buffer space never blocks
|
||||
testBlock(never, func() {
|
||||
ch := make(chan int, async)
|
||||
ch <- 7
|
||||
})
|
||||
|
||||
// receiving from a closed channel never blocks
|
||||
testBlock(never, func() {
|
||||
for i := 0; i < 10; i++ {
|
||||
if <-closedch != 0 {
|
||||
panic("expected zero value when reading from closed channel")
|
||||
}
|
||||
if x, ok := <-closedch; x != 0 || ok {
|
||||
println("closedch:", x, ok)
|
||||
panic("expected 0, false from closed channel")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// sending to a closed channel panics.
|
||||
testPanic(always, func() {
|
||||
closedch <- 7
|
||||
})
|
||||
|
||||
// receiving from a non-ready channel always blocks
|
||||
testBlock(always, func() {
|
||||
ch := make(chan int)
|
||||
<-ch
|
||||
})
|
||||
|
||||
// empty selects always block
|
||||
testBlock(always, func() {
|
||||
select {}
|
||||
})
|
||||
|
||||
// selects with only nil channels always block
|
||||
testBlock(always, func() {
|
||||
select {
|
||||
case <-nilch:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
testBlock(always, func() {
|
||||
select {
|
||||
case nilch <- 7:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
testBlock(always, func() {
|
||||
select {
|
||||
case <-nilch:
|
||||
unreachable()
|
||||
case nilch <- 7:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
|
||||
// selects with non-ready non-nil channels always block
|
||||
testBlock(always, func() {
|
||||
ch := make(chan int)
|
||||
select {
|
||||
case <-ch:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
|
||||
// selects with default cases don't block
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
default:
|
||||
}
|
||||
})
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
case <-nilch:
|
||||
unreachable()
|
||||
default:
|
||||
}
|
||||
})
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
case nilch <- 7:
|
||||
unreachable()
|
||||
default:
|
||||
}
|
||||
})
|
||||
|
||||
// selects with ready channels don't block
|
||||
testBlock(never, func() {
|
||||
ch := make(chan int, async)
|
||||
select {
|
||||
case ch <- 7:
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
testBlock(never, func() {
|
||||
ch := make(chan int, async)
|
||||
ch <- 7
|
||||
select {
|
||||
case <-ch:
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
|
||||
// selects with closed channels behave like ordinary operations
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
case <-closedch:
|
||||
}
|
||||
})
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
case x := (<-closedch):
|
||||
_ = x
|
||||
}
|
||||
})
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
case x, ok := (<-closedch):
|
||||
_, _ = x, ok
|
||||
}
|
||||
})
|
||||
testPanic(always, func() {
|
||||
select {
|
||||
case closedch <- 7:
|
||||
}
|
||||
})
|
||||
|
||||
// select should not get confused if it sees itself
|
||||
testBlock(always, func() {
|
||||
c := make(chan int)
|
||||
select {
|
||||
case c <- 1:
|
||||
case <-c:
|
||||
}
|
||||
})
|
||||
}
|
||||
31
test/chan/select4.go
Normal file
31
test/chan/select4.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// run
|
||||
|
||||
// Copyright 2010 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
|
||||
|
||||
// Test that a select statement proceeds when a value is ready.
|
||||
|
||||
package main
|
||||
|
||||
func f() *int {
|
||||
println("BUG: called f")
|
||||
return new(int)
|
||||
}
|
||||
|
||||
func main() {
|
||||
var x struct {
|
||||
a int
|
||||
}
|
||||
c := make(chan int, 1)
|
||||
c1 := make(chan int)
|
||||
c <- 42
|
||||
select {
|
||||
case *f() = <-c1:
|
||||
// nothing
|
||||
case x.a = <-c:
|
||||
if x.a != 42 {
|
||||
println("BUG:", x.a)
|
||||
}
|
||||
}
|
||||
}
|
||||
481
test/chan/select5.go
Normal file
481
test/chan/select5.go
Normal file
@@ -0,0 +1,481 @@
|
||||
// runoutput
|
||||
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Generate test of channel operations and simple selects.
|
||||
// The output of this program is compiled and run to do the
|
||||
// actual test.
|
||||
|
||||
// Each test does only one real send or receive at a time, but phrased
|
||||
// in various ways that the compiler may or may not rewrite
|
||||
// into simpler expressions.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func main() {
|
||||
out := bufio.NewWriter(os.Stdout)
|
||||
fmt.Fprintln(out, header)
|
||||
a := new(arg)
|
||||
|
||||
// Generate each test as a separate function to avoid
|
||||
// hitting the gc optimizer with one enormous function.
|
||||
// If we name all the functions init we don't have to
|
||||
// maintain a list of which ones to run.
|
||||
do := func(t *template.Template) {
|
||||
for ; next(); a.reset() {
|
||||
fmt.Fprintln(out, `func init() {`)
|
||||
run(t, a, out)
|
||||
fmt.Fprintln(out, `}`)
|
||||
}
|
||||
}
|
||||
|
||||
do(recv)
|
||||
do(send)
|
||||
do(recvOrder)
|
||||
do(sendOrder)
|
||||
do(nonblock)
|
||||
|
||||
fmt.Fprintln(out, "//", a.nreset, "cases")
|
||||
out.Flush()
|
||||
}
|
||||
|
||||
func run(t *template.Template, a interface{}, out io.Writer) {
|
||||
if err := t.Execute(out, a); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type arg struct {
|
||||
def bool
|
||||
nreset int
|
||||
}
|
||||
|
||||
func (a *arg) Maybe() bool {
|
||||
return maybe()
|
||||
}
|
||||
|
||||
func (a *arg) MaybeDefault() bool {
|
||||
if a.def {
|
||||
return false
|
||||
}
|
||||
a.def = maybe()
|
||||
return a.def
|
||||
}
|
||||
|
||||
func (a *arg) MustDefault() bool {
|
||||
return !a.def
|
||||
}
|
||||
|
||||
func (a *arg) reset() {
|
||||
a.def = false
|
||||
a.nreset++
|
||||
}
|
||||
|
||||
const header = `// GENERATED BY select5.go; DO NOT EDIT
|
||||
|
||||
package main
|
||||
|
||||
// channel is buffered so test is single-goroutine.
|
||||
// we are not interested in the concurrency aspects
|
||||
// of select, just testing that the right calls happen.
|
||||
var c = make(chan int, 1)
|
||||
var nilch chan int
|
||||
var n = 1
|
||||
var x int
|
||||
var i interface{}
|
||||
var dummy = make(chan int)
|
||||
var m = make(map[int]int)
|
||||
var order = 0
|
||||
|
||||
func f(p *int) *int {
|
||||
return p
|
||||
}
|
||||
|
||||
// check order of operations by ensuring that
|
||||
// successive calls to checkorder have increasing o values.
|
||||
func checkorder(o int) {
|
||||
if o <= order {
|
||||
println("invalid order", o, "after", order)
|
||||
panic("order")
|
||||
}
|
||||
order = o
|
||||
}
|
||||
|
||||
func fc(c chan int, o int) chan int {
|
||||
checkorder(o)
|
||||
return c
|
||||
}
|
||||
|
||||
func fp(p *int, o int) *int {
|
||||
checkorder(o)
|
||||
return p
|
||||
}
|
||||
|
||||
func fn(n, o int) int {
|
||||
checkorder(o)
|
||||
return n
|
||||
}
|
||||
|
||||
func die(x int) {
|
||||
println("have", x, "want", n)
|
||||
panic("chan")
|
||||
}
|
||||
|
||||
func main() {
|
||||
// everything happens in init funcs
|
||||
}
|
||||
`
|
||||
|
||||
func parse(name, s string) *template.Template {
|
||||
t, err := template.New(name).Parse(s)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("%q: %s", name, err))
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
var recv = parse("recv", `
|
||||
{{/* Send n, receive it one way or another into x, check that they match. */}}
|
||||
c <- n
|
||||
{{if .Maybe}}
|
||||
x = <-c
|
||||
{{else}}
|
||||
select {
|
||||
{{/* Blocking or non-blocking, before the receive. */}}
|
||||
{{/* The compiler implements two-case select where one is default with custom code, */}}
|
||||
{{/* so test the default branch both before and after the send. */}}
|
||||
{{if .MaybeDefault}}
|
||||
default:
|
||||
panic("nonblock")
|
||||
{{end}}
|
||||
{{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}}
|
||||
{{if .Maybe}}
|
||||
case x = <-c:
|
||||
{{else}}{{if .Maybe}}
|
||||
case *f(&x) = <-c:
|
||||
{{else}}{{if .Maybe}}
|
||||
case y := <-c:
|
||||
x = y
|
||||
{{else}}{{if .Maybe}}
|
||||
case i = <-c:
|
||||
x = i.(int)
|
||||
{{else}}
|
||||
case m[13] = <-c:
|
||||
x = m[13]
|
||||
{{end}}{{end}}{{end}}{{end}}
|
||||
{{/* Blocking or non-blocking again, after the receive. */}}
|
||||
{{if .MaybeDefault}}
|
||||
default:
|
||||
panic("nonblock")
|
||||
{{end}}
|
||||
{{/* Dummy send, receive to keep compiler from optimizing select. */}}
|
||||
{{if .Maybe}}
|
||||
case dummy <- 1:
|
||||
panic("dummy send")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case <-dummy:
|
||||
panic("dummy receive")
|
||||
{{end}}
|
||||
{{/* Nil channel send, receive to keep compiler from optimizing select. */}}
|
||||
{{if .Maybe}}
|
||||
case nilch <- 1:
|
||||
panic("nilch send")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case <-nilch:
|
||||
panic("nilch recv")
|
||||
{{end}}
|
||||
}
|
||||
{{end}}
|
||||
if x != n {
|
||||
die(x)
|
||||
}
|
||||
n++
|
||||
`)
|
||||
|
||||
var recvOrder = parse("recvOrder", `
|
||||
{{/* Send n, receive it one way or another into x, check that they match. */}}
|
||||
{{/* Check order of operations along the way by calling functions that check */}}
|
||||
{{/* that the argument sequence is strictly increasing. */}}
|
||||
order = 0
|
||||
c <- n
|
||||
{{if .Maybe}}
|
||||
{{/* Outside of select, left-to-right rule applies. */}}
|
||||
{{/* (Inside select, assignment waits until case is chosen, */}}
|
||||
{{/* so right hand side happens before anything on left hand side. */}}
|
||||
*fp(&x, 1) = <-fc(c, 2)
|
||||
{{else}}{{if .Maybe}}
|
||||
m[fn(13, 1)] = <-fc(c, 2)
|
||||
x = m[13]
|
||||
{{else}}
|
||||
select {
|
||||
{{/* Blocking or non-blocking, before the receive. */}}
|
||||
{{/* The compiler implements two-case select where one is default with custom code, */}}
|
||||
{{/* so test the default branch both before and after the send. */}}
|
||||
{{if .MaybeDefault}}
|
||||
default:
|
||||
panic("nonblock")
|
||||
{{end}}
|
||||
{{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}}
|
||||
{{if .Maybe}}
|
||||
case *fp(&x, 100) = <-fc(c, 1):
|
||||
{{else}}{{if .Maybe}}
|
||||
case y := <-fc(c, 1):
|
||||
x = y
|
||||
{{else}}{{if .Maybe}}
|
||||
case i = <-fc(c, 1):
|
||||
x = i.(int)
|
||||
{{else}}
|
||||
case m[fn(13, 100)] = <-fc(c, 1):
|
||||
x = m[13]
|
||||
{{end}}{{end}}{{end}}
|
||||
{{/* Blocking or non-blocking again, after the receive. */}}
|
||||
{{if .MaybeDefault}}
|
||||
default:
|
||||
panic("nonblock")
|
||||
{{end}}
|
||||
{{/* Dummy send, receive to keep compiler from optimizing select. */}}
|
||||
{{if .Maybe}}
|
||||
case fc(dummy, 2) <- fn(1, 3):
|
||||
panic("dummy send")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case <-fc(dummy, 4):
|
||||
panic("dummy receive")
|
||||
{{end}}
|
||||
{{/* Nil channel send, receive to keep compiler from optimizing select. */}}
|
||||
{{if .Maybe}}
|
||||
case fc(nilch, 5) <- fn(1, 6):
|
||||
panic("nilch send")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case <-fc(nilch, 7):
|
||||
panic("nilch recv")
|
||||
{{end}}
|
||||
}
|
||||
{{end}}{{end}}
|
||||
if x != n {
|
||||
die(x)
|
||||
}
|
||||
n++
|
||||
`)
|
||||
|
||||
var send = parse("send", `
|
||||
{{/* Send n one way or another, receive it into x, check that they match. */}}
|
||||
{{if .Maybe}}
|
||||
c <- n
|
||||
{{else}}
|
||||
select {
|
||||
{{/* Blocking or non-blocking, before the receive (same reason as in recv). */}}
|
||||
{{if .MaybeDefault}}
|
||||
default:
|
||||
panic("nonblock")
|
||||
{{end}}
|
||||
{{/* Send c <- n. No real special cases here, because no values come back */}}
|
||||
{{/* from the send operation. */}}
|
||||
case c <- n:
|
||||
{{/* Blocking or non-blocking. */}}
|
||||
{{if .MaybeDefault}}
|
||||
default:
|
||||
panic("nonblock")
|
||||
{{end}}
|
||||
{{/* Dummy send, receive to keep compiler from optimizing select. */}}
|
||||
{{if .Maybe}}
|
||||
case dummy <- 1:
|
||||
panic("dummy send")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case <-dummy:
|
||||
panic("dummy receive")
|
||||
{{end}}
|
||||
{{/* Nil channel send, receive to keep compiler from optimizing select. */}}
|
||||
{{if .Maybe}}
|
||||
case nilch <- 1:
|
||||
panic("nilch send")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case <-nilch:
|
||||
panic("nilch recv")
|
||||
{{end}}
|
||||
}
|
||||
{{end}}
|
||||
x = <-c
|
||||
if x != n {
|
||||
die(x)
|
||||
}
|
||||
n++
|
||||
`)
|
||||
|
||||
var sendOrder = parse("sendOrder", `
|
||||
{{/* Send n one way or another, receive it into x, check that they match. */}}
|
||||
{{/* Check order of operations along the way by calling functions that check */}}
|
||||
{{/* that the argument sequence is strictly increasing. */}}
|
||||
order = 0
|
||||
{{if .Maybe}}
|
||||
fc(c, 1) <- fn(n, 2)
|
||||
{{else}}
|
||||
select {
|
||||
{{/* Blocking or non-blocking, before the receive (same reason as in recv). */}}
|
||||
{{if .MaybeDefault}}
|
||||
default:
|
||||
panic("nonblock")
|
||||
{{end}}
|
||||
{{/* Send c <- n. No real special cases here, because no values come back */}}
|
||||
{{/* from the send operation. */}}
|
||||
case fc(c, 1) <- fn(n, 2):
|
||||
{{/* Blocking or non-blocking. */}}
|
||||
{{if .MaybeDefault}}
|
||||
default:
|
||||
panic("nonblock")
|
||||
{{end}}
|
||||
{{/* Dummy send, receive to keep compiler from optimizing select. */}}
|
||||
{{if .Maybe}}
|
||||
case fc(dummy, 3) <- fn(1, 4):
|
||||
panic("dummy send")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case <-fc(dummy, 5):
|
||||
panic("dummy receive")
|
||||
{{end}}
|
||||
{{/* Nil channel send, receive to keep compiler from optimizing select. */}}
|
||||
{{if .Maybe}}
|
||||
case fc(nilch, 6) <- fn(1, 7):
|
||||
panic("nilch send")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case <-fc(nilch, 8):
|
||||
panic("nilch recv")
|
||||
{{end}}
|
||||
}
|
||||
{{end}}
|
||||
x = <-c
|
||||
if x != n {
|
||||
die(x)
|
||||
}
|
||||
n++
|
||||
`)
|
||||
|
||||
var nonblock = parse("nonblock", `
|
||||
x = n
|
||||
{{/* Test various combinations of non-blocking operations. */}}
|
||||
{{/* Receive assignments must not edit or even attempt to compute the address of the lhs. */}}
|
||||
select {
|
||||
{{if .MaybeDefault}}
|
||||
default:
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case dummy <- 1:
|
||||
panic("dummy <- 1")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case nilch <- 1:
|
||||
panic("nilch <- 1")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case <-dummy:
|
||||
panic("<-dummy")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case x = <-dummy:
|
||||
panic("<-dummy x")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case **(**int)(nil) = <-dummy:
|
||||
panic("<-dummy (and didn't crash saving result!)")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case <-nilch:
|
||||
panic("<-nilch")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case x = <-nilch:
|
||||
panic("<-nilch x")
|
||||
{{end}}
|
||||
{{if .Maybe}}
|
||||
case **(**int)(nil) = <-nilch:
|
||||
panic("<-nilch (and didn't crash saving result!)")
|
||||
{{end}}
|
||||
{{if .MustDefault}}
|
||||
default:
|
||||
{{end}}
|
||||
}
|
||||
if x != n {
|
||||
die(x)
|
||||
}
|
||||
n++
|
||||
`)
|
||||
|
||||
// Code for enumerating all possible paths through
|
||||
// some logic. The logic should call choose(n) when
|
||||
// it wants to choose between n possibilities.
|
||||
// On successive runs through the logic, choose(n)
|
||||
// will return 0, 1, ..., n-1. The helper maybe() is
|
||||
// similar but returns true and then false.
|
||||
//
|
||||
// Given a function gen that generates an output
|
||||
// using choose and maybe, code can generate all
|
||||
// possible outputs using
|
||||
//
|
||||
// for next() {
|
||||
// gen()
|
||||
// }
|
||||
|
||||
type choice struct {
|
||||
i, n int
|
||||
}
|
||||
|
||||
var choices []choice
|
||||
var cp int = -1
|
||||
|
||||
func maybe() bool {
|
||||
return choose(2) == 0
|
||||
}
|
||||
|
||||
func choose(n int) int {
|
||||
if cp >= len(choices) {
|
||||
// never asked this before: start with 0.
|
||||
choices = append(choices, choice{0, n})
|
||||
cp = len(choices)
|
||||
return 0
|
||||
}
|
||||
// otherwise give recorded answer
|
||||
if n != choices[cp].n {
|
||||
panic("inconsistent choices")
|
||||
}
|
||||
i := choices[cp].i
|
||||
cp++
|
||||
return i
|
||||
}
|
||||
|
||||
func next() bool {
|
||||
if cp < 0 {
|
||||
// start a new round
|
||||
cp = 0
|
||||
return true
|
||||
}
|
||||
|
||||
// increment last choice sequence
|
||||
cp = len(choices) - 1
|
||||
for cp >= 0 && choices[cp].i == choices[cp].n-1 {
|
||||
cp--
|
||||
}
|
||||
if cp < 0 {
|
||||
choices = choices[:0]
|
||||
return false
|
||||
}
|
||||
choices[cp].i++
|
||||
choices = choices[:cp+1]
|
||||
cp = 0
|
||||
return true
|
||||
}
|
||||
34
test/chan/select6.go
Normal file
34
test/chan/select6.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// run
|
||||
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Test for select: Issue 2075
|
||||
// A bug in select corrupts channel queues of failed cases
|
||||
// if there are multiple waiters on those channels and the
|
||||
// select is the last in the queue. If further waits are made
|
||||
// on the channel without draining it first then those waiters
|
||||
// will never wake up. In the code below c1 is such a channel.
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c1 := make(chan bool)
|
||||
c2 := make(chan bool)
|
||||
c3 := make(chan bool)
|
||||
go func() { <-c1 }()
|
||||
go func() {
|
||||
select {
|
||||
case <-c1:
|
||||
panic("dummy")
|
||||
case <-c2:
|
||||
c3 <- true
|
||||
}
|
||||
<-c1
|
||||
}()
|
||||
go func() { c2 <- true }()
|
||||
<-c3
|
||||
c1 <- true
|
||||
c1 <- true
|
||||
}
|
||||
68
test/chan/select7.go
Normal file
68
test/chan/select7.go
Normal file
@@ -0,0 +1,68 @@
|
||||
// run
|
||||
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Test select when discarding a value.
|
||||
|
||||
package main
|
||||
|
||||
import "runtime"
|
||||
|
||||
func recv1(c <-chan int) {
|
||||
<-c
|
||||
}
|
||||
|
||||
func recv2(c <-chan int) {
|
||||
select {
|
||||
case <-c:
|
||||
}
|
||||
}
|
||||
|
||||
func recv3(c <-chan int) {
|
||||
c2 := make(chan int)
|
||||
select {
|
||||
case <-c:
|
||||
case <-c2:
|
||||
}
|
||||
}
|
||||
|
||||
func send1(recv func(<-chan int)) {
|
||||
c := make(chan int)
|
||||
go recv(c)
|
||||
runtime.Gosched()
|
||||
c <- 1
|
||||
}
|
||||
|
||||
func send2(recv func(<-chan int)) {
|
||||
c := make(chan int)
|
||||
go recv(c)
|
||||
runtime.Gosched()
|
||||
select {
|
||||
case c <- 1:
|
||||
}
|
||||
}
|
||||
|
||||
func send3(recv func(<-chan int)) {
|
||||
c := make(chan int)
|
||||
go recv(c)
|
||||
runtime.Gosched()
|
||||
c2 := make(chan int)
|
||||
select {
|
||||
case c <- 1:
|
||||
case c2 <- 1:
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
send1(recv1)
|
||||
send2(recv1)
|
||||
send3(recv1)
|
||||
send1(recv2)
|
||||
send2(recv2)
|
||||
send3(recv2)
|
||||
send1(recv3)
|
||||
send2(recv3)
|
||||
send3(recv3)
|
||||
}
|
||||
55
test/chan/select8.go
Normal file
55
test/chan/select8.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// run
|
||||
|
||||
// Copyright 2019 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.
|
||||
|
||||
// Test break statements in a select.
|
||||
// Gccgo had a bug in handling this.
|
||||
// Test 1,2,3-case selects, so it covers both the general
|
||||
// code path and the specialized optimizations for one-
|
||||
// and two-case selects.
|
||||
|
||||
package main
|
||||
|
||||
var ch = make(chan int)
|
||||
|
||||
func main() {
|
||||
go func() {
|
||||
for {
|
||||
ch <- 5
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
break
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
select {
|
||||
default:
|
||||
break
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
break
|
||||
panic("unreachable")
|
||||
default:
|
||||
break
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
break
|
||||
panic("unreachable")
|
||||
case ch <- 10:
|
||||
panic("unreachable")
|
||||
default:
|
||||
break
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
37
test/chan/sendstmt.go
Normal file
37
test/chan/sendstmt.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// run
|
||||
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Test various parsing cases that are a little
|
||||
// different now that send is a statement, not an expression.
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
chanchan()
|
||||
sendprec()
|
||||
}
|
||||
|
||||
func chanchan() {
|
||||
cc := make(chan chan int, 1)
|
||||
c := make(chan int, 1)
|
||||
cc <- c
|
||||
select {
|
||||
case <-cc <- 2:
|
||||
default:
|
||||
panic("nonblock")
|
||||
}
|
||||
if <-c != 2 {
|
||||
panic("bad receive")
|
||||
}
|
||||
}
|
||||
|
||||
func sendprec() {
|
||||
c := make(chan bool, 1)
|
||||
c <- false || true // not a syntax error: same as c <- (false || true)
|
||||
if !<-c {
|
||||
panic("sent false")
|
||||
}
|
||||
}
|
||||
56
test/chan/sieve1.go
Normal file
56
test/chan/sieve1.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// run
|
||||
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Test concurrency primitives: classical inefficient concurrent prime sieve.
|
||||
|
||||
// Generate primes up to 100 using channels, checking the results.
|
||||
// This sieve consists of a linear chain of divisibility filters,
|
||||
// equivalent to trial-dividing each n by all primes p ≤ n.
|
||||
|
||||
package main
|
||||
|
||||
// Send the sequence 2, 3, 4, ... to channel 'ch'.
|
||||
func Generate(ch chan<- int) {
|
||||
for i := 2; ; i++ {
|
||||
ch <- i // Send 'i' to channel 'ch'.
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the values from channel 'in' to channel 'out',
|
||||
// removing those divisible by 'prime'.
|
||||
func Filter(in <-chan int, out chan<- int, prime int) {
|
||||
for i := range in { // Loop over values received from 'in'.
|
||||
if i%prime != 0 {
|
||||
out <- i // Send 'i' to channel 'out'.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The prime sieve: Daisy-chain Filter processes together.
|
||||
func Sieve(primes chan<- int) {
|
||||
ch := make(chan int) // Create a new channel.
|
||||
go Generate(ch) // Start Generate() as a subprocess.
|
||||
for {
|
||||
// Note that ch is different on each iteration.
|
||||
prime := <-ch
|
||||
primes <- prime
|
||||
ch1 := make(chan int)
|
||||
go Filter(ch, ch1, prime)
|
||||
ch = ch1
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
primes := make(chan int)
|
||||
go Sieve(primes)
|
||||
a := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}
|
||||
for i := 0; i < len(a); i++ {
|
||||
if x := <-primes; x != a[i] {
|
||||
println(x, " != ", a[i])
|
||||
panic("fail")
|
||||
}
|
||||
}
|
||||
}
|
||||
188
test/chan/sieve2.go
Normal file
188
test/chan/sieve2.go
Normal file
@@ -0,0 +1,188 @@
|
||||
// run
|
||||
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Test concurrency primitives: prime sieve of Eratosthenes.
|
||||
|
||||
// Generate primes up to 100 using channels, checking the results.
|
||||
// This sieve is Eratosthenesque and only considers odd candidates.
|
||||
// See discussion at <http://blog.onideas.ws/eratosthenes.go>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"container/ring"
|
||||
)
|
||||
|
||||
// Return a chan of odd numbers, starting from 5.
|
||||
func odds() chan int {
|
||||
out := make(chan int, 50)
|
||||
go func() {
|
||||
n := 5
|
||||
for {
|
||||
out <- n
|
||||
n += 2
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
// Return a chan of odd multiples of the prime number p, starting from p*p.
|
||||
func multiples(p int) chan int {
|
||||
out := make(chan int, 10)
|
||||
go func() {
|
||||
n := p * p
|
||||
for {
|
||||
out <- n
|
||||
n += 2 * p
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
type PeekCh struct {
|
||||
head int
|
||||
ch chan int
|
||||
}
|
||||
|
||||
// Heap of PeekCh, sorting by head values, satisfies Heap interface.
|
||||
type PeekChHeap []*PeekCh
|
||||
|
||||
func (h *PeekChHeap) Less(i, j int) bool {
|
||||
return (*h)[i].head < (*h)[j].head
|
||||
}
|
||||
|
||||
func (h *PeekChHeap) Swap(i, j int) {
|
||||
(*h)[i], (*h)[j] = (*h)[j], (*h)[i]
|
||||
}
|
||||
|
||||
func (h *PeekChHeap) Len() int {
|
||||
return len(*h)
|
||||
}
|
||||
|
||||
func (h *PeekChHeap) Pop() (v interface{}) {
|
||||
*h, v = (*h)[:h.Len()-1], (*h)[h.Len()-1]
|
||||
return
|
||||
}
|
||||
|
||||
func (h *PeekChHeap) Push(v interface{}) {
|
||||
*h = append(*h, v.(*PeekCh))
|
||||
}
|
||||
|
||||
// Return a channel to serve as a sending proxy to 'out'.
|
||||
// Use a goroutine to receive values from 'out' and store them
|
||||
// in an expanding buffer, so that sending to 'out' never blocks.
|
||||
func sendproxy(out chan<- int) chan<- int {
|
||||
proxy := make(chan int, 10)
|
||||
go func() {
|
||||
n := 16 // the allocated size of the circular queue
|
||||
first := ring.New(n)
|
||||
last := first
|
||||
var c chan<- int
|
||||
var e int
|
||||
for {
|
||||
c = out
|
||||
if first == last {
|
||||
// buffer empty: disable output
|
||||
c = nil
|
||||
} else {
|
||||
e = first.Value.(int)
|
||||
}
|
||||
select {
|
||||
case e = <-proxy:
|
||||
last.Value = e
|
||||
if last.Next() == first {
|
||||
// buffer full: expand it
|
||||
last.Link(ring.New(n))
|
||||
n *= 2
|
||||
}
|
||||
last = last.Next()
|
||||
case c <- e:
|
||||
first = first.Next()
|
||||
}
|
||||
}
|
||||
}()
|
||||
return proxy
|
||||
}
|
||||
|
||||
// Return a chan int of primes.
|
||||
func Sieve() chan int {
|
||||
// The output values.
|
||||
out := make(chan int, 10)
|
||||
out <- 2
|
||||
out <- 3
|
||||
|
||||
// The channel of all composites to be eliminated in increasing order.
|
||||
composites := make(chan int, 50)
|
||||
|
||||
// The feedback loop.
|
||||
primes := make(chan int, 10)
|
||||
primes <- 3
|
||||
|
||||
// Merge channels of multiples of 'primes' into 'composites'.
|
||||
go func() {
|
||||
var h PeekChHeap
|
||||
min := 15
|
||||
for {
|
||||
m := multiples(<-primes)
|
||||
head := <-m
|
||||
for min < head {
|
||||
composites <- min
|
||||
minchan := heap.Pop(&h).(*PeekCh)
|
||||
min = minchan.head
|
||||
minchan.head = <-minchan.ch
|
||||
heap.Push(&h, minchan)
|
||||
}
|
||||
for min == head {
|
||||
minchan := heap.Pop(&h).(*PeekCh)
|
||||
min = minchan.head
|
||||
minchan.head = <-minchan.ch
|
||||
heap.Push(&h, minchan)
|
||||
}
|
||||
composites <- head
|
||||
heap.Push(&h, &PeekCh{<-m, m})
|
||||
}
|
||||
}()
|
||||
|
||||
// Sieve out 'composites' from 'candidates'.
|
||||
go func() {
|
||||
// In order to generate the nth prime we only need multiples of
|
||||
// primes ≤ sqrt(nth prime). Thus, the merging goroutine will
|
||||
// receive from 'primes' much slower than this goroutine
|
||||
// will send to it, making the buffer accumulate and block this
|
||||
// goroutine from sending, causing a deadlock. The solution is to
|
||||
// use a proxy goroutine to do automatic buffering.
|
||||
primes := sendproxy(primes)
|
||||
|
||||
candidates := odds()
|
||||
p := <-candidates
|
||||
|
||||
for {
|
||||
c := <-composites
|
||||
for p < c {
|
||||
primes <- p
|
||||
out <- p
|
||||
p = <-candidates
|
||||
}
|
||||
if p == c {
|
||||
p = <-candidates
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func main() {
|
||||
primes := Sieve()
|
||||
a := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}
|
||||
for i := 0; i < len(a); i++ {
|
||||
if x := <-primes; x != a[i] {
|
||||
println(x, " != ", a[i])
|
||||
panic("fail")
|
||||
}
|
||||
}
|
||||
}
|
||||
16
test/chan/zerosize.go
Normal file
16
test/chan/zerosize.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// run
|
||||
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Test making channels of a zero-sized type.
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
_ = make(chan [0]byte)
|
||||
_ = make(chan [0]byte, 1)
|
||||
_ = make(chan struct{})
|
||||
_ = make(chan struct{}, 1)
|
||||
}
|
||||
Reference in New Issue
Block a user