mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-12-25 14:28:58 +00:00
remove unused file
This commit is contained in:
parent
745a165b6f
commit
2284164524
8
.gitignore
vendored
8
.gitignore
vendored
@ -14,3 +14,11 @@ _book
|
||||
*.epub
|
||||
*.mobi
|
||||
*.pdf
|
||||
|
||||
# user defined
|
||||
vendor
|
||||
docs
|
||||
cover_bgd.png
|
||||
cover_patch.png
|
||||
/images/cover.png
|
||||
/images/gopher/go_lang_mascot_by_kirael_art-d7kunhu.gif
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
TODO
|
@ -1,2 +0,0 @@
|
||||
**練習 1.1:** 脩改echo程序,使其能夠打印os.Args[0]。
|
||||
|
@ -1 +0,0 @@
|
||||
**練習 1.2:** 脩改echo程序,使其打印value和index,每個value和index顯示一行。
|
@ -1,2 +0,0 @@
|
||||
**練習 1.3:** 上手實踐前麫提到的strings.Join和直接Println,併觀察輸齣結果的區彆。
|
||||
|
@ -1,2 +0,0 @@
|
||||
**練習 1.4:** 脩改dup2,使其可以打印重復的行分彆齣現在哪些文件。
|
||||
|
@ -1 +0,0 @@
|
||||
**練習 1.5:** 脩改前麫的Lissajous程序裏的調色闆,由緑色改為黑色。我們可以用color.RGBA{0xRR, 0xGG, 0xBB}來得到#RRGGBB這個色值,三個十六進製的字符串分彆代錶紅、緑、藍像素。
|
@ -1,2 +0,0 @@
|
||||
**練習 1.6:** 脩改Lissajous程序,脩改其調色闆來生成更豐富的顔色,然後脩改SetColorIndex的第三個參數,看看顯示結果吧。
|
||||
|
@ -1,2 +0,0 @@
|
||||
**練習 1.7:** 函數調用io.Copy(dst, src)會從src中讀取內容,併將讀到的結果寫入到dst中,使用這個函數替代掉例子中的ioutil.ReadAll來拷貝響應結構體到os.Stdout,避免申請一個緩衝區(例子中的b)來存儲。記得處理io.Copy返迴結果中的錯誤。
|
||||
|
@ -1,2 +0,0 @@
|
||||
**練習 1.8:** 脩改fetch這個範例,如果輸入的url參數沒有http://前綴的話,為這個url加上該前綴。你可能會用到strings.HasPrefix這個函數。
|
||||
|
@ -1,2 +0,0 @@
|
||||
**練習 1.9:** 脩改fetch打印齣HTTP協議的狀態碼,可以從resp.Status變量得到該狀態碼。
|
||||
|
@ -1,2 +0,0 @@
|
||||
**練習 1.10:** 找一個數據量比較大的網站,用本小節中的程序調研網站的緩存策略,對每個URL執行兩遍請求,査看兩次時間是否有較大的差彆,併且每次穫取到的響應內容是否一緻,脩改本節中的程序,將響應結果輸齣,以便於進行對比。
|
||||
|
@ -1,2 +0,0 @@
|
||||
**練習 1.11:** Try fetchall with longer argument lists, such as samples from the top million web sites available at alexa.com. How does the program behave if a web site just doesn’t respond? (Section 8.9 describes mechanisms for coping in such cases.)
|
||||
|
@ -1,2 +0,0 @@
|
||||
**練習 1.12:** 脩改Lissajour服務,從URL讀取變量,比如你可以訪問http://localhost:8000/?cycles=20這個URL,這樣訪問可以將程序裏的cycles默認的5脩改為20。字符串轉換為數字可以調用strconv.Atoi函數。你可以在dodoc裏査看strconv.Atoi的詳細說明。
|
||||
|
2123
exercise/ex-ch1.html
2123
exercise/ex-ch1.html
File diff suppressed because it is too large
Load Diff
2111
exercise/ex.html
2111
exercise/ex.html
File diff suppressed because it is too large
Load Diff
48933
tools/STPhrases.txt
48933
tools/STPhrases.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,62 +0,0 @@
|
||||
// Copyright 2013 <chaishushan{AT}gmail.com>. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ingore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f, err := os.Open("./TSCharacters.txt")
|
||||
if err != nil {
|
||||
log.Fatal("open failed:", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
br := bufio.NewReader(f)
|
||||
|
||||
var out bytes.Buffer
|
||||
fmt.Fprintf(&out, `
|
||||
// Copyright 2013 <chaishushan{AT}gmail.com>. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Auto generated by go generate, DO NOT EDIT !!!
|
||||
|
||||
package main
|
||||
|
||||
var _TSCharactersMap = map[rune]rune{
|
||||
`[1:])
|
||||
for i := 0; i < 1<<20; i++ {
|
||||
data, isPrefix, err := br.ReadLine()
|
||||
if err != nil || isPrefix {
|
||||
break
|
||||
}
|
||||
if !utf8.ValidString(string(data)) {
|
||||
continue
|
||||
}
|
||||
|
||||
line := strings.Replace(string(data), "\t", " ", -1)
|
||||
ss := strings.Split(string(line), " ")
|
||||
|
||||
if len(ss) >= 2 {
|
||||
tw := strings.TrimSpace(ss[0])
|
||||
zh := strings.TrimSpace(ss[1])
|
||||
fmt.Fprintf(&out, "\t'%s': '%s',\n", tw, zh)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(&out, "}\n")
|
||||
|
||||
ioutil.WriteFile("z_TSCharacters.go", []byte(out.Bytes()), 0666)
|
||||
}
|
21
vendor/gopl.io/README.md
generated
vendored
21
vendor/gopl.io/README.md
generated
vendored
@ -1,21 +0,0 @@
|
||||
# The Go Programming Language
|
||||
|
||||
This repository provides the downloadable example programs
|
||||
for the book, "The Go Programming Language"; see http://www.gopl.io.
|
||||
|
||||
These example programs are licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a>.<br/>
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png"/></a>
|
||||
|
||||
You can download, build, and run the programs with the following commands:
|
||||
|
||||
$ export GOPATH=$HOME/gobook # choose workspace directory
|
||||
$ go get gopl.io/ch1/helloworld # fetch, build, install
|
||||
$ $GOPATH/bin/helloworld # run
|
||||
Hello, 世界
|
||||
|
||||
Many of the programs contain comments of the form `//!+` and `//!-`.
|
||||
These comments bracket the parts of the programs that are excerpted in the
|
||||
book; you can safely ignore them. In a few cases, programs
|
||||
have been reformatted in an unnatural way so that they can be presented
|
||||
in stages in the book.
|
||||
|
31
vendor/gopl.io/ch1/dup1/main.go
generated
vendored
31
vendor/gopl.io/ch1/dup1/main.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 8.
|
||||
//!+
|
||||
|
||||
// Dup1 prints the text of each line that appears more than
|
||||
// once in the standard input, preceded by its count.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
counts := make(map[string]int)
|
||||
input := bufio.NewScanner(os.Stdin)
|
||||
for input.Scan() {
|
||||
counts[input.Text()]++
|
||||
}
|
||||
// NOTE: ignoring potential errors from input.Err()
|
||||
for line, n := range counts {
|
||||
if n > 1 {
|
||||
fmt.Printf("%d\t%s\n", n, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
48
vendor/gopl.io/ch1/dup2/main.go
generated
vendored
48
vendor/gopl.io/ch1/dup2/main.go
generated
vendored
@ -1,48 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 10.
|
||||
//!+
|
||||
|
||||
// Dup2 prints the count and text of lines that appear more than once
|
||||
// in the input. It reads from stdin or from a list of named files.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
counts := make(map[string]int)
|
||||
files := os.Args[1:]
|
||||
if len(files) == 0 {
|
||||
countLines(os.Stdin, counts)
|
||||
} else {
|
||||
for _, arg := range files {
|
||||
f, err := os.Open(arg)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
|
||||
continue
|
||||
}
|
||||
countLines(f, counts)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
for line, n := range counts {
|
||||
if n > 1 {
|
||||
fmt.Printf("%d\t%s\n", n, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func countLines(f *os.File, counts map[string]int) {
|
||||
input := bufio.NewScanner(f)
|
||||
for input.Scan() {
|
||||
counts[input.Text()]++
|
||||
}
|
||||
// NOTE: ignoring potential errors from input.Err()
|
||||
}
|
||||
|
||||
//!-
|
38
vendor/gopl.io/ch1/dup3/main.go
generated
vendored
38
vendor/gopl.io/ch1/dup3/main.go
generated
vendored
@ -1,38 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 12.
|
||||
|
||||
//!+
|
||||
|
||||
// Dup3 prints the count and text of lines that
|
||||
// appear more than once in the named input files.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
counts := make(map[string]int)
|
||||
for _, filename := range os.Args[1:] {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "dup3: %v\n", err)
|
||||
continue
|
||||
}
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
counts[line]++
|
||||
}
|
||||
}
|
||||
for line, n := range counts {
|
||||
if n > 1 {
|
||||
fmt.Printf("%d\t%s\n", n, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
24
vendor/gopl.io/ch1/echo1/main.go
generated
vendored
24
vendor/gopl.io/ch1/echo1/main.go
generated
vendored
@ -1,24 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 4.
|
||||
//!+
|
||||
|
||||
// Echo1 prints its command-line arguments.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var s, sep string
|
||||
for i := 1; i < len(os.Args); i++ {
|
||||
s += sep + os.Args[i]
|
||||
sep = " "
|
||||
}
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
//!-
|
24
vendor/gopl.io/ch1/echo2/main.go
generated
vendored
24
vendor/gopl.io/ch1/echo2/main.go
generated
vendored
@ -1,24 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 6.
|
||||
//!+
|
||||
|
||||
// Echo2 prints its command-line arguments.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s, sep := "", ""
|
||||
for _, arg := range os.Args[1:] {
|
||||
s += sep + arg
|
||||
sep = " "
|
||||
}
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
//!-
|
20
vendor/gopl.io/ch1/echo3/main.go
generated
vendored
20
vendor/gopl.io/ch1/echo3/main.go
generated
vendored
@ -1,20 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 8.
|
||||
|
||||
// Echo3 prints its command-line arguments.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//!+
|
||||
func main() {
|
||||
fmt.Println(strings.Join(os.Args[1:], " "))
|
||||
}
|
||||
|
||||
//!-
|
34
vendor/gopl.io/ch1/fetch/main.go
generated
vendored
34
vendor/gopl.io/ch1/fetch/main.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 16.
|
||||
//!+
|
||||
|
||||
// Fetch prints the content found at each specified URL.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for _, url := range os.Args[1:] {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("%s", b)
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
49
vendor/gopl.io/ch1/fetchall/main.go
generated
vendored
49
vendor/gopl.io/ch1/fetchall/main.go
generated
vendored
@ -1,49 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 17.
|
||||
//!+
|
||||
|
||||
// Fetchall fetches URLs in parallel and reports their times and sizes.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
start := time.Now()
|
||||
ch := make(chan string)
|
||||
for _, url := range os.Args[1:] {
|
||||
go fetch(url, ch) // start a goroutine
|
||||
}
|
||||
for range os.Args[1:] {
|
||||
fmt.Println(<-ch) // receive from channel ch
|
||||
}
|
||||
fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())
|
||||
}
|
||||
|
||||
func fetch(url string, ch chan<- string) {
|
||||
start := time.Now()
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
ch <- fmt.Sprint(err) // send to channel ch
|
||||
return
|
||||
}
|
||||
|
||||
nbytes, err := io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close() // don't leak resources
|
||||
if err != nil {
|
||||
ch <- fmt.Sprintf("while reading %s: %v", url, err)
|
||||
return
|
||||
}
|
||||
secs := time.Since(start).Seconds()
|
||||
ch <- fmt.Sprintf("%.2fs %7d %s", secs, nbytes, url)
|
||||
}
|
||||
|
||||
//!-
|
16
vendor/gopl.io/ch1/helloworld/main.go
generated
vendored
16
vendor/gopl.io/ch1/helloworld/main.go
generated
vendored
@ -1,16 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 1.
|
||||
|
||||
// Helloworld is our first Go program.
|
||||
//!+
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello, 世界")
|
||||
}
|
||||
|
||||
//!-
|
86
vendor/gopl.io/ch1/lissajous/main.go
generated
vendored
86
vendor/gopl.io/ch1/lissajous/main.go
generated
vendored
@ -1,86 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// Run with "web" command-line argument for web server.
|
||||
// See page 13.
|
||||
//!+main
|
||||
|
||||
// Lissajous generates GIF animations of random Lissajous figures.
|
||||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/gif"
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
)
|
||||
|
||||
//!-main
|
||||
// Packages not needed by version in book.
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
//!+main
|
||||
|
||||
var palette = []color.Color{color.White, color.Black}
|
||||
|
||||
const (
|
||||
whiteIndex = 0 // first color in palette
|
||||
blackIndex = 1 // next color in palette
|
||||
)
|
||||
|
||||
func main() {
|
||||
//!-main
|
||||
// The sequence of images is deterministic unless we seed
|
||||
// the pseudo-random number generator using the current time.
|
||||
// Thanks to Randall McPherson for pointing out the omission.
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
|
||||
if len(os.Args) > 1 && os.Args[1] == "web" {
|
||||
//!+http
|
||||
handler := func(w http.ResponseWriter, r *http.Request) {
|
||||
lissajous(w)
|
||||
}
|
||||
http.HandleFunc("/", handler)
|
||||
//!-http
|
||||
log.Fatal(http.ListenAndServe("localhost:8000", nil))
|
||||
return
|
||||
}
|
||||
//!+main
|
||||
lissajous(os.Stdout)
|
||||
}
|
||||
|
||||
func lissajous(out io.Writer) {
|
||||
const (
|
||||
cycles = 5 // number of complete x oscillator revolutions
|
||||
res = 0.001 // angular resolution
|
||||
size = 100 // image canvas covers [-size..+size]
|
||||
nframes = 64 // number of animation frames
|
||||
delay = 8 // delay between frames in 10ms units
|
||||
)
|
||||
freq := rand.Float64() * 3.0 // relative frequency of y oscillator
|
||||
anim := gif.GIF{LoopCount: nframes}
|
||||
phase := 0.0 // phase difference
|
||||
for i := 0; i < nframes; i++ {
|
||||
rect := image.Rect(0, 0, 2*size+1, 2*size+1)
|
||||
img := image.NewPaletted(rect, palette)
|
||||
for t := 0.0; t < cycles*2*math.Pi; t += res {
|
||||
x := math.Sin(t)
|
||||
y := math.Sin(t*freq + phase)
|
||||
img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5),
|
||||
blackIndex)
|
||||
}
|
||||
phase += 0.1
|
||||
anim.Delay = append(anim.Delay, delay)
|
||||
anim.Image = append(anim.Image, img)
|
||||
}
|
||||
gif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors
|
||||
}
|
||||
|
||||
//!-main
|
26
vendor/gopl.io/ch1/server1/main.go
generated
vendored
26
vendor/gopl.io/ch1/server1/main.go
generated
vendored
@ -1,26 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 19.
|
||||
//!+
|
||||
|
||||
// Server1 is a minimal "echo" server.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", handler) // each request calls handler
|
||||
log.Fatal(http.ListenAndServe("localhost:8000", nil))
|
||||
}
|
||||
|
||||
// handler echoes the Path component of the requested URL.
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
|
||||
}
|
||||
|
||||
//!-
|
41
vendor/gopl.io/ch1/server2/main.go
generated
vendored
41
vendor/gopl.io/ch1/server2/main.go
generated
vendored
@ -1,41 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 20.
|
||||
//!+
|
||||
|
||||
// Server2 is a minimal "echo" and counter server.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var mu sync.Mutex
|
||||
var count int
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", handler)
|
||||
http.HandleFunc("/count", counter)
|
||||
log.Fatal(http.ListenAndServe("localhost:8000", nil))
|
||||
}
|
||||
|
||||
// handler echoes the Path component of the requested URL.
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
mu.Lock()
|
||||
count++
|
||||
mu.Unlock()
|
||||
fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
|
||||
}
|
||||
|
||||
// counter echoes the number of calls so far.
|
||||
func counter(w http.ResponseWriter, r *http.Request) {
|
||||
mu.Lock()
|
||||
fmt.Fprintf(w, "Count %d\n", count)
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
//!-
|
37
vendor/gopl.io/ch1/server3/main.go
generated
vendored
37
vendor/gopl.io/ch1/server3/main.go
generated
vendored
@ -1,37 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 21.
|
||||
|
||||
// Server3 is an "echo" server that displays request parameters.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", handler)
|
||||
log.Fatal(http.ListenAndServe("localhost:8000", nil))
|
||||
}
|
||||
|
||||
//!+handler
|
||||
// handler echoes the HTTP request.
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "%s %s %s\n", r.Method, r.URL, r.Proto)
|
||||
for k, v := range r.Header {
|
||||
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
|
||||
}
|
||||
fmt.Fprintf(w, "Host = %q\n", r.Host)
|
||||
fmt.Fprintf(w, "RemoteAddr = %q\n", r.RemoteAddr)
|
||||
if err := r.ParseForm(); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
for k, v := range r.Form {
|
||||
fmt.Fprintf(w, "Form[%q] = %q\n", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
//!-handler
|
19
vendor/gopl.io/ch10/cross/main.go
generated
vendored
19
vendor/gopl.io/ch10/cross/main.go
generated
vendored
@ -1,19 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 295.
|
||||
|
||||
// The cross command prints the values of GOOS and GOARCH for this target.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
//!+
|
||||
func main() {
|
||||
fmt.Println(runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
//!-
|
52
vendor/gopl.io/ch10/jpeg/main.go
generated
vendored
52
vendor/gopl.io/ch10/jpeg/main.go
generated
vendored
@ -1,52 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 287.
|
||||
|
||||
//!+main
|
||||
|
||||
// The jpeg command reads a PNG image from the standard input
|
||||
// and writes it as a JPEG image to the standard output.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
_ "image/png" // register PNG decoder
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := toJPEG(os.Stdin, os.Stdout); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "jpeg: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func toJPEG(in io.Reader, out io.Writer) error {
|
||||
img, kind, err := image.Decode(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, "Input format =", kind)
|
||||
return jpeg.Encode(out, img, &jpeg.Options{Quality: 95})
|
||||
}
|
||||
|
||||
//!-main
|
||||
|
||||
/*
|
||||
//!+with
|
||||
$ go build gopl.io/ch3/mandelbrot
|
||||
$ go build gopl.io/ch10/jpeg
|
||||
$ ./mandelbrot | ./jpeg >mandelbrot.jpg
|
||||
Input format = png
|
||||
//!-with
|
||||
|
||||
//!+without
|
||||
$ go build gopl.io/ch10/jpeg
|
||||
$ ./mandelbrot | ./jpeg >mandelbrot.jpg
|
||||
jpeg: image: unknown format
|
||||
//!-without
|
||||
*/
|
41
vendor/gopl.io/ch11/echo/echo.go
generated
vendored
41
vendor/gopl.io/ch11/echo/echo.go
generated
vendored
@ -1,41 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 308.
|
||||
//!+
|
||||
|
||||
// Echo prints its command-line arguments.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
n = flag.Bool("n", false, "omit trailing newline")
|
||||
s = flag.String("s", " ", "separator")
|
||||
)
|
||||
|
||||
var out io.Writer = os.Stdout // modified during testing
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if err := echo(!*n, *s, flag.Args()); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "echo: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func echo(newline bool, sep string, args []string) error {
|
||||
fmt.Fprint(out, strings.Join(args, sep))
|
||||
if newline {
|
||||
fmt.Fprintln(out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//!-
|
45
vendor/gopl.io/ch11/echo/echo_test.go
generated
vendored
45
vendor/gopl.io/ch11/echo/echo_test.go
generated
vendored
@ -1,45 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// Test of echo command. Run with: go test gopl.io/ch11/echo
|
||||
|
||||
//!+
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEcho(t *testing.T) {
|
||||
var tests = []struct {
|
||||
newline bool
|
||||
sep string
|
||||
args []string
|
||||
want string
|
||||
}{
|
||||
{true, "", []string{}, "\n"},
|
||||
{false, "", []string{}, ""},
|
||||
{true, "\t", []string{"one", "two", "three"}, "one\ttwo\tthree\n"},
|
||||
{true, ",", []string{"a", "b", "c"}, "a,b,c\n"},
|
||||
{false, ":", []string{"1", "2", "3"}, "1:2:3"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
descr := fmt.Sprintf("echo(%v, %q, %q)",
|
||||
test.newline, test.sep, test.args)
|
||||
|
||||
out = new(bytes.Buffer) // captured output
|
||||
if err := echo(test.newline, test.sep, test.args); err != nil {
|
||||
t.Errorf("%s failed: %v", descr, err)
|
||||
continue
|
||||
}
|
||||
got := out.(*bytes.Buffer).String()
|
||||
if got != test.want {
|
||||
t.Errorf("%s = %q, want %q", descr, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
45
vendor/gopl.io/ch11/storage1/storage.go
generated
vendored
45
vendor/gopl.io/ch11/storage1/storage.go
generated
vendored
@ -1,45 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 311.
|
||||
|
||||
// Package storage is part of a hypothetical cloud storage server.
|
||||
//!+main
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/smtp"
|
||||
)
|
||||
|
||||
var usage = make(map[string]int64)
|
||||
|
||||
func bytesInUse(username string) int64 { return usage[username] }
|
||||
|
||||
// Email sender configuration.
|
||||
// NOTE: never put passwords in source code!
|
||||
const sender = "notifications@example.com"
|
||||
const password = "correcthorsebatterystaple"
|
||||
const hostname = "smtp.example.com"
|
||||
|
||||
const template = `Warning: you are using %d bytes of storage,
|
||||
%d%% of your quota.`
|
||||
|
||||
func CheckQuota(username string) {
|
||||
used := bytesInUse(username)
|
||||
const quota = 1000000000 // 1GB
|
||||
percent := 100 * used / quota
|
||||
if percent < 90 {
|
||||
return // OK
|
||||
}
|
||||
msg := fmt.Sprintf(template, used, percent)
|
||||
auth := smtp.PlainAuth("", sender, password, hostname)
|
||||
err := smtp.SendMail(hostname+":587", auth, sender,
|
||||
[]string{username}, []byte(msg))
|
||||
if err != nil {
|
||||
log.Printf("smtp.SendMail(%s) failed: %s", username, err)
|
||||
}
|
||||
}
|
||||
|
||||
//!-main
|
53
vendor/gopl.io/ch11/storage2/quota_test.go
generated
vendored
53
vendor/gopl.io/ch11/storage2/quota_test.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
//!+test
|
||||
package storage
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCheckQuotaNotifiesUser(t *testing.T) {
|
||||
var notifiedUser, notifiedMsg string
|
||||
notifyUser = func(user, msg string) {
|
||||
notifiedUser, notifiedMsg = user, msg
|
||||
}
|
||||
|
||||
const user = "joe@example.org"
|
||||
usage[user] = 980000000 // simulate a 980MB-used condition
|
||||
|
||||
CheckQuota(user)
|
||||
if notifiedUser == "" && notifiedMsg == "" {
|
||||
t.Fatalf("notifyUser not called")
|
||||
}
|
||||
if notifiedUser != user {
|
||||
t.Errorf("wrong user (%s) notified, want %s",
|
||||
notifiedUser, user)
|
||||
}
|
||||
const wantSubstring = "98% of your quota"
|
||||
if !strings.Contains(notifiedMsg, wantSubstring) {
|
||||
t.Errorf("unexpected notification message <<%s>>, "+
|
||||
"want substring %q", notifiedMsg, wantSubstring)
|
||||
}
|
||||
}
|
||||
|
||||
//!-test
|
||||
|
||||
/*
|
||||
//!+defer
|
||||
func TestCheckQuotaNotifiesUser(t *testing.T) {
|
||||
// Save and restore original notifyUser.
|
||||
saved := notifyUser
|
||||
defer func() { notifyUser = saved }()
|
||||
|
||||
// Install the test's fake notifyUser.
|
||||
var notifiedUser, notifiedMsg string
|
||||
notifyUser = func(user, msg string) {
|
||||
notifiedUser, notifiedMsg = user, msg
|
||||
}
|
||||
// ...rest of test...
|
||||
}
|
||||
//!-defer
|
||||
*/
|
49
vendor/gopl.io/ch11/storage2/storage.go
generated
vendored
49
vendor/gopl.io/ch11/storage2/storage.go
generated
vendored
@ -1,49 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 312.
|
||||
|
||||
// Package storage is part of a hypothetical cloud storage server.
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/smtp"
|
||||
)
|
||||
|
||||
var usage = make(map[string]int64)
|
||||
|
||||
func bytesInUse(username string) int64 { return usage[username] }
|
||||
|
||||
// E-mail sender configuration.
|
||||
// NOTE: never put passwords in source code!
|
||||
const sender = "notifications@example.com"
|
||||
const password = "correcthorsebatterystaple"
|
||||
const hostname = "smtp.example.com"
|
||||
|
||||
const template = `Warning: you are using %d bytes of storage,
|
||||
%d%% of your quota.`
|
||||
|
||||
//!+factored
|
||||
var notifyUser = func(username, msg string) {
|
||||
auth := smtp.PlainAuth("", sender, password, hostname)
|
||||
err := smtp.SendMail(hostname+":587", auth, sender,
|
||||
[]string{username}, []byte(msg))
|
||||
if err != nil {
|
||||
log.Printf("smtp.SendEmail(%s) failed: %s", username, err)
|
||||
}
|
||||
}
|
||||
|
||||
func CheckQuota(username string) {
|
||||
used := bytesInUse(username)
|
||||
const quota = 1000000000 // 1GB
|
||||
percent := 100 * used / quota
|
||||
if percent < 90 {
|
||||
return // OK
|
||||
}
|
||||
msg := fmt.Sprintf(template, used, percent)
|
||||
notifyUser(username, msg)
|
||||
}
|
||||
|
||||
//!-factored
|
21
vendor/gopl.io/ch11/word1/word.go
generated
vendored
21
vendor/gopl.io/ch11/word1/word.go
generated
vendored
@ -1,21 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 303.
|
||||
//!+
|
||||
|
||||
// Package word provides utilities for word games.
|
||||
package word
|
||||
|
||||
// IsPalindrome reports whether s reads the same forward and backward.
|
||||
// (Our first attempt.)
|
||||
func IsPalindrome(s string) bool {
|
||||
for i := range s {
|
||||
if s[i] != s[len(s)-1-i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//!-
|
43
vendor/gopl.io/ch11/word1/word_test.go
generated
vendored
43
vendor/gopl.io/ch11/word1/word_test.go
generated
vendored
@ -1,43 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
//!+test
|
||||
package word
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPalindrome(t *testing.T) {
|
||||
if !IsPalindrome("detartrated") {
|
||||
t.Error(`IsPalindrome("detartrated") = false`)
|
||||
}
|
||||
if !IsPalindrome("kayak") {
|
||||
t.Error(`IsPalindrome("kayak") = false`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonPalindrome(t *testing.T) {
|
||||
if IsPalindrome("palindrome") {
|
||||
t.Error(`IsPalindrome("palindrome") = true`)
|
||||
}
|
||||
}
|
||||
|
||||
//!-test
|
||||
|
||||
// The tests below are expected to fail.
|
||||
// See package gopl.io/ch11/word2 for the fix.
|
||||
|
||||
//!+more
|
||||
func TestFrenchPalindrome(t *testing.T) {
|
||||
if !IsPalindrome("été") {
|
||||
t.Error(`IsPalindrome("été") = false`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanalPalindrome(t *testing.T) {
|
||||
input := "A man, a plan, a canal: Panama"
|
||||
if !IsPalindrome(input) {
|
||||
t.Errorf(`IsPalindrome(%q) = false`, input)
|
||||
}
|
||||
}
|
||||
|
||||
//!-more
|
29
vendor/gopl.io/ch11/word2/word.go
generated
vendored
29
vendor/gopl.io/ch11/word2/word.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 305.
|
||||
//!+
|
||||
|
||||
// Package word provides utilities for word games.
|
||||
package word
|
||||
|
||||
import "unicode"
|
||||
|
||||
// IsPalindrome reports whether s reads the same forward and backward.
|
||||
// Letter case is ignored, as are non-letters.
|
||||
func IsPalindrome(s string) bool {
|
||||
var letters []rune
|
||||
for _, r := range s {
|
||||
if unicode.IsLetter(r) {
|
||||
letters = append(letters, unicode.ToLower(r))
|
||||
}
|
||||
}
|
||||
for i := range letters {
|
||||
if letters[i] != letters[len(letters)-1-i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//!-
|
148
vendor/gopl.io/ch11/word2/word_test.go
generated
vendored
148
vendor/gopl.io/ch11/word2/word_test.go
generated
vendored
@ -1,148 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package word
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
//!+bench
|
||||
|
||||
import "testing"
|
||||
|
||||
//!-bench
|
||||
|
||||
//!+test
|
||||
func TestIsPalindrome(t *testing.T) {
|
||||
var tests = []struct {
|
||||
input string
|
||||
want bool
|
||||
}{
|
||||
{"", true},
|
||||
{"a", true},
|
||||
{"aa", true},
|
||||
{"ab", false},
|
||||
{"kayak", true},
|
||||
{"detartrated", true},
|
||||
{"A man, a plan, a canal: Panama", true},
|
||||
{"Evil I did dwell; lewd did I live.", true},
|
||||
{"Able was I ere I saw Elba", true},
|
||||
{"été", true},
|
||||
{"Et se resservir, ivresse reste.", true},
|
||||
{"palindrome", false}, // non-palindrome
|
||||
{"desserts", false}, // semi-palindrome
|
||||
}
|
||||
for _, test := range tests {
|
||||
if got := IsPalindrome(test.input); got != test.want {
|
||||
t.Errorf("IsPalindrome(%q) = %v", test.input, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-test
|
||||
|
||||
//!+bench
|
||||
func BenchmarkIsPalindrome(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsPalindrome("A man, a plan, a canal: Panama")
|
||||
}
|
||||
}
|
||||
|
||||
//!-bench
|
||||
|
||||
//!+example
|
||||
|
||||
func ExampleIsPalindrome() {
|
||||
fmt.Println(IsPalindrome("A man, a plan, a canal: Panama"))
|
||||
fmt.Println(IsPalindrome("palindrome"))
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
//!-example
|
||||
|
||||
/*
|
||||
//!+random
|
||||
import "math/rand"
|
||||
|
||||
//!-random
|
||||
*/
|
||||
|
||||
//!+random
|
||||
// randomPalindrome returns a palindrome whose length and contents
|
||||
// are derived from the pseudo-random number generator rng.
|
||||
func randomPalindrome(rng *rand.Rand) string {
|
||||
n := rng.Intn(25) // random length up to 24
|
||||
runes := make([]rune, n)
|
||||
for i := 0; i < (n+1)/2; i++ {
|
||||
r := rune(rng.Intn(0x1000)) // random rune up to '\u0999'
|
||||
runes[i] = r
|
||||
runes[n-1-i] = r
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
func TestRandomPalindromes(t *testing.T) {
|
||||
// Initialize a pseudo-random number generator.
|
||||
seed := time.Now().UTC().UnixNano()
|
||||
t.Logf("Random seed: %d", seed)
|
||||
rng := rand.New(rand.NewSource(seed))
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
p := randomPalindrome(rng)
|
||||
if !IsPalindrome(p) {
|
||||
t.Errorf("IsPalindrome(%q) = false", p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-random
|
||||
|
||||
/*
|
||||
// Answer for Exercicse 11.1: Modify randomPalindrome to exercise
|
||||
// IsPalindrome's handling of punctuation and spaces.
|
||||
|
||||
// WARNING: the conversion r -> upper -> lower doesn't preserve
|
||||
// the value of r in some cases, e.g., µ Μ, ſ S, ı I
|
||||
|
||||
// randomPalindrome returns a palindrome whose length and contents
|
||||
// are derived from the pseudo-random number generator rng.
|
||||
func randomNoisyPalindrome(rng *rand.Rand) string {
|
||||
n := rng.Intn(25) // random length up to 24
|
||||
runes := make([]rune, n)
|
||||
for i := 0; i < (n+1)/2; i++ {
|
||||
r := rune(rng.Intn(0x200)) // random rune up to \u99
|
||||
runes[i] = r
|
||||
r1 := r
|
||||
if unicode.IsLetter(r) && unicode.IsLower(r) {
|
||||
r = unicode.ToUpper(r)
|
||||
if unicode.ToLower(r) != r1 {
|
||||
fmt.Printf("cap? %c %c\n", r1, r)
|
||||
}
|
||||
}
|
||||
runes[n-1-i] = r
|
||||
}
|
||||
return "?" + string(runes) + "!"
|
||||
}
|
||||
|
||||
func TestRandomNoisyPalindromes(t *testing.T) {
|
||||
// Initialize a pseudo-random number generator.
|
||||
seed := time.Now().UTC().UnixNano()
|
||||
t.Logf("Random seed: %d", seed)
|
||||
rng := rand.New(rand.NewSource(seed))
|
||||
|
||||
n := 0
|
||||
for i := 0; i < 1000; i++ {
|
||||
p := randomNoisyPalindrome(rng)
|
||||
if !IsPalindrome(p) {
|
||||
t.Errorf("IsNoisyPalindrome(%q) = false", p)
|
||||
n++
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "fail = %d\n", n)
|
||||
}
|
||||
*/
|
90
vendor/gopl.io/ch12/display/display.go
generated
vendored
90
vendor/gopl.io/ch12/display/display.go
generated
vendored
@ -1,90 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 333.
|
||||
|
||||
// Package display provides a means to display structured data.
|
||||
package display
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//!+Display
|
||||
|
||||
func Display(name string, x interface{}) {
|
||||
fmt.Printf("Display %s (%T):\n", name, x)
|
||||
display(name, reflect.ValueOf(x))
|
||||
}
|
||||
|
||||
//!-Display
|
||||
|
||||
// formatAtom formats a value without inspecting its internal structure.
|
||||
// It is a copy of the the function in gopl.io/ch11/format.
|
||||
func formatAtom(v reflect.Value) string {
|
||||
switch v.Kind() {
|
||||
case reflect.Invalid:
|
||||
return "invalid"
|
||||
case reflect.Int, reflect.Int8, reflect.Int16,
|
||||
reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(v.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16,
|
||||
reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return strconv.FormatUint(v.Uint(), 10)
|
||||
// ...floating-point and complex cases omitted for brevity...
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
return "true"
|
||||
}
|
||||
return "false"
|
||||
case reflect.String:
|
||||
return strconv.Quote(v.String())
|
||||
case reflect.Chan, reflect.Func, reflect.Ptr,
|
||||
reflect.Slice, reflect.Map:
|
||||
return v.Type().String() + " 0x" +
|
||||
strconv.FormatUint(uint64(v.Pointer()), 16)
|
||||
default: // reflect.Array, reflect.Struct, reflect.Interface
|
||||
return v.Type().String() + " value"
|
||||
}
|
||||
}
|
||||
|
||||
//!+display
|
||||
func display(path string, v reflect.Value) {
|
||||
switch v.Kind() {
|
||||
case reflect.Invalid:
|
||||
fmt.Printf("%s = invalid\n", path)
|
||||
case reflect.Slice, reflect.Array:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
display(fmt.Sprintf("%s[%d]", path, i), v.Index(i))
|
||||
}
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
fieldPath := fmt.Sprintf("%s.%s", path, v.Type().Field(i).Name)
|
||||
display(fieldPath, v.Field(i))
|
||||
}
|
||||
case reflect.Map:
|
||||
for _, key := range v.MapKeys() {
|
||||
display(fmt.Sprintf("%s[%s]", path,
|
||||
formatAtom(key)), v.MapIndex(key))
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if v.IsNil() {
|
||||
fmt.Printf("%s = nil\n", path)
|
||||
} else {
|
||||
display(fmt.Sprintf("(*%s)", path), v.Elem())
|
||||
}
|
||||
case reflect.Interface:
|
||||
if v.IsNil() {
|
||||
fmt.Printf("%s = nil\n", path)
|
||||
} else {
|
||||
fmt.Printf("%s.type = %s\n", path, v.Elem().Type())
|
||||
display(path+".value", v.Elem())
|
||||
}
|
||||
default: // basic types, channels, funcs
|
||||
fmt.Printf("%s = %s\n", path, formatAtom(v))
|
||||
}
|
||||
}
|
||||
|
||||
//!-display
|
259
vendor/gopl.io/ch12/display/display_test.go
generated
vendored
259
vendor/gopl.io/ch12/display/display_test.go
generated
vendored
@ -1,259 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package display
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"gopl.io/ch7/eval"
|
||||
)
|
||||
|
||||
// NOTE: we can't use !+..!- comments to excerpt these tests
|
||||
// into the book because it defeats the Example mechanism,
|
||||
// which requires the // Output comment to be at the end
|
||||
// of the function.
|
||||
|
||||
func Example_expr() {
|
||||
e, _ := eval.Parse("sqrt(A / pi)")
|
||||
Display("e", e)
|
||||
// Output:
|
||||
// Display e (eval.call):
|
||||
// e.fn = "sqrt"
|
||||
// e.args[0].type = eval.binary
|
||||
// e.args[0].value.op = 47
|
||||
// e.args[0].value.x.type = eval.Var
|
||||
// e.args[0].value.x.value = "A"
|
||||
// e.args[0].value.y.type = eval.Var
|
||||
// e.args[0].value.y.value = "pi"
|
||||
}
|
||||
|
||||
func Example_slice() {
|
||||
Display("slice", []*int{new(int), nil})
|
||||
// Output:
|
||||
// Display slice ([]*int):
|
||||
// (*slice[0]) = 0
|
||||
// slice[1] = nil
|
||||
}
|
||||
|
||||
func Example_nilInterface() {
|
||||
var w io.Writer
|
||||
Display("w", w)
|
||||
// Output:
|
||||
// Display w (<nil>):
|
||||
// w = invalid
|
||||
}
|
||||
|
||||
func Example_ptrToInterface() {
|
||||
var w io.Writer
|
||||
Display("&w", &w)
|
||||
// Output:
|
||||
// Display &w (*io.Writer):
|
||||
// (*&w) = nil
|
||||
}
|
||||
|
||||
func Example_struct() {
|
||||
Display("x", struct{ x interface{} }{3})
|
||||
// Output:
|
||||
// Display x (struct { x interface {} }):
|
||||
// x.x.type = int
|
||||
// x.x.value = 3
|
||||
}
|
||||
|
||||
func Example_interface() {
|
||||
var i interface{} = 3
|
||||
Display("i", i)
|
||||
// Output:
|
||||
// Display i (int):
|
||||
// i = 3
|
||||
}
|
||||
|
||||
func Example_ptrToInterface2() {
|
||||
var i interface{} = 3
|
||||
Display("&i", &i)
|
||||
// Output:
|
||||
// Display &i (*interface {}):
|
||||
// (*&i).type = int
|
||||
// (*&i).value = 3
|
||||
}
|
||||
|
||||
func Example_array() {
|
||||
Display("x", [1]interface{}{3})
|
||||
// Output:
|
||||
// Display x ([1]interface {}):
|
||||
// x[0].type = int
|
||||
// x[0].value = 3
|
||||
}
|
||||
|
||||
func Example_movie() {
|
||||
//!+movie
|
||||
type Movie struct {
|
||||
Title, Subtitle string
|
||||
Year int
|
||||
Color bool
|
||||
Actor map[string]string
|
||||
Oscars []string
|
||||
Sequel *string
|
||||
}
|
||||
//!-movie
|
||||
//!+strangelove
|
||||
strangelove := Movie{
|
||||
Title: "Dr. Strangelove",
|
||||
Subtitle: "How I Learned to Stop Worrying and Love the Bomb",
|
||||
Year: 1964,
|
||||
Color: false,
|
||||
Actor: map[string]string{
|
||||
"Dr. Strangelove": "Peter Sellers",
|
||||
"Grp. Capt. Lionel Mandrake": "Peter Sellers",
|
||||
"Pres. Merkin Muffley": "Peter Sellers",
|
||||
"Gen. Buck Turgidson": "George C. Scott",
|
||||
"Brig. Gen. Jack D. Ripper": "Sterling Hayden",
|
||||
`Maj. T.J. "King" Kong`: "Slim Pickens",
|
||||
},
|
||||
|
||||
Oscars: []string{
|
||||
"Best Actor (Nomin.)",
|
||||
"Best Adapted Screenplay (Nomin.)",
|
||||
"Best Director (Nomin.)",
|
||||
"Best Picture (Nomin.)",
|
||||
},
|
||||
}
|
||||
//!-strangelove
|
||||
Display("strangelove", strangelove)
|
||||
|
||||
// We don't use an Output: comment since displaying
|
||||
// a map is nondeterministic.
|
||||
/*
|
||||
//!+output
|
||||
Display strangelove (display.Movie):
|
||||
strangelove.Title = "Dr. Strangelove"
|
||||
strangelove.Subtitle = "How I Learned to Stop Worrying and Love the Bomb"
|
||||
strangelove.Year = 1964
|
||||
strangelove.Color = false
|
||||
strangelove.Actor["Gen. Buck Turgidson"] = "George C. Scott"
|
||||
strangelove.Actor["Brig. Gen. Jack D. Ripper"] = "Sterling Hayden"
|
||||
strangelove.Actor["Maj. T.J. \"King\" Kong"] = "Slim Pickens"
|
||||
strangelove.Actor["Dr. Strangelove"] = "Peter Sellers"
|
||||
strangelove.Actor["Grp. Capt. Lionel Mandrake"] = "Peter Sellers"
|
||||
strangelove.Actor["Pres. Merkin Muffley"] = "Peter Sellers"
|
||||
strangelove.Oscars[0] = "Best Actor (Nomin.)"
|
||||
strangelove.Oscars[1] = "Best Adapted Screenplay (Nomin.)"
|
||||
strangelove.Oscars[2] = "Best Director (Nomin.)"
|
||||
strangelove.Oscars[3] = "Best Picture (Nomin.)"
|
||||
strangelove.Sequel = nil
|
||||
//!-output
|
||||
*/
|
||||
}
|
||||
|
||||
// This test ensures that the program terminates without crashing.
|
||||
func Test(t *testing.T) {
|
||||
// Some other values (YMMV)
|
||||
Display("os.Stderr", os.Stderr)
|
||||
// Output:
|
||||
// Display os.Stderr (*os.File):
|
||||
// (*(*os.Stderr).file).fd = 2
|
||||
// (*(*os.Stderr).file).name = "/dev/stderr"
|
||||
// (*(*os.Stderr).file).nepipe = 0
|
||||
|
||||
var w io.Writer = os.Stderr
|
||||
Display("&w", &w)
|
||||
// Output:
|
||||
// Display &w (*io.Writer):
|
||||
// (*&w).type = *os.File
|
||||
// (*(*(*&w).value).file).fd = 2
|
||||
// (*(*(*&w).value).file).name = "/dev/stderr"
|
||||
// (*(*(*&w).value).file).nepipe = 0
|
||||
|
||||
var locker sync.Locker = new(sync.Mutex)
|
||||
Display("(&locker)", &locker)
|
||||
// Output:
|
||||
// Display (&locker) (*sync.Locker):
|
||||
// (*(&locker)).type = *sync.Mutex
|
||||
// (*(*(&locker)).value).state = 0
|
||||
// (*(*(&locker)).value).sema = 0
|
||||
|
||||
Display("locker", locker)
|
||||
// Output:
|
||||
// Display locker (*sync.Mutex):
|
||||
// (*locker).state = 0
|
||||
// (*locker).sema = 0
|
||||
// (*(&locker)) = nil
|
||||
|
||||
locker = nil
|
||||
Display("(&locker)", &locker)
|
||||
// Output:
|
||||
// Display (&locker) (*sync.Locker):
|
||||
// (*(&locker)) = nil
|
||||
|
||||
ips, _ := net.LookupHost("golang.org")
|
||||
Display("ips", ips)
|
||||
// Output:
|
||||
// Display ips ([]string):
|
||||
// ips[0] = "173.194.68.141"
|
||||
// ips[1] = "2607:f8b0:400d:c06::8d"
|
||||
|
||||
// Even metarecursion! (YMMV)
|
||||
Display("rV", reflect.ValueOf(os.Stderr))
|
||||
// Output:
|
||||
// Display rV (reflect.Value):
|
||||
// (*rV.typ).size = 8
|
||||
// (*rV.typ).ptrdata = 8
|
||||
// (*rV.typ).hash = 871609668
|
||||
// (*rV.typ)._ = 0
|
||||
// ...
|
||||
|
||||
// a pointer that points to itself
|
||||
type P *P
|
||||
var p P
|
||||
p = &p
|
||||
if false {
|
||||
Display("p", p)
|
||||
// Output:
|
||||
// Display p (display.P):
|
||||
// ...stuck, no output...
|
||||
}
|
||||
|
||||
// a map that contains itself
|
||||
type M map[string]M
|
||||
m := make(M)
|
||||
m[""] = m
|
||||
if false {
|
||||
Display("m", m)
|
||||
// Output:
|
||||
// Display m (display.M):
|
||||
// ...stuck, no output...
|
||||
}
|
||||
|
||||
// a slice that contains itself
|
||||
type S []S
|
||||
s := make(S, 1)
|
||||
s[0] = s
|
||||
if false {
|
||||
Display("s", s)
|
||||
// Output:
|
||||
// Display s (display.S):
|
||||
// ...stuck, no output...
|
||||
}
|
||||
|
||||
// a linked list that eats its own tail
|
||||
type Cycle struct {
|
||||
Value int
|
||||
Tail *Cycle
|
||||
}
|
||||
var c Cycle
|
||||
c = Cycle{42, &c}
|
||||
if false {
|
||||
Display("c", c)
|
||||
// Output:
|
||||
// Display c (display.Cycle):
|
||||
// c.Value = 42
|
||||
// (*c.Tail).Value = 42
|
||||
// (*(*c.Tail).Tail).Value = 42
|
||||
// ...ad infinitum...
|
||||
}
|
||||
}
|
44
vendor/gopl.io/ch12/format/format.go
generated
vendored
44
vendor/gopl.io/ch12/format/format.go
generated
vendored
@ -1,44 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 332.
|
||||
|
||||
// Package format provides an Any function that can format any value.
|
||||
//!+
|
||||
package format
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Any formats any value as a string.
|
||||
func Any(value interface{}) string {
|
||||
return formatAtom(reflect.ValueOf(value))
|
||||
}
|
||||
|
||||
// formatAtom formats a value without inspecting its internal structure.
|
||||
func formatAtom(v reflect.Value) string {
|
||||
switch v.Kind() {
|
||||
case reflect.Invalid:
|
||||
return "invalid"
|
||||
case reflect.Int, reflect.Int8, reflect.Int16,
|
||||
reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(v.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16,
|
||||
reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return strconv.FormatUint(v.Uint(), 10)
|
||||
// ...floating-point and complex cases omitted for brevity...
|
||||
case reflect.Bool:
|
||||
return strconv.FormatBool(v.Bool())
|
||||
case reflect.String:
|
||||
return strconv.Quote(v.String())
|
||||
case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Slice, reflect.Map:
|
||||
return v.Type().String() + " 0x" +
|
||||
strconv.FormatUint(uint64(v.Pointer()), 16)
|
||||
default: // reflect.Array, reflect.Struct, reflect.Interface
|
||||
return v.Type().String() + " value"
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
24
vendor/gopl.io/ch12/format/format_test.go
generated
vendored
24
vendor/gopl.io/ch12/format/format_test.go
generated
vendored
@ -1,24 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package format_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopl.io/ch12/format"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
// The pointer values are just examples, and may vary from run to run.
|
||||
//!+time
|
||||
var x int64 = 1
|
||||
var d time.Duration = 1 * time.Nanosecond
|
||||
fmt.Println(format.Any(x)) // "1"
|
||||
fmt.Println(format.Any(d)) // "1"
|
||||
fmt.Println(format.Any([]int64{x})) // "[]int64 0x8202b87b0"
|
||||
fmt.Println(format.Any([]time.Duration{d})) // "[]time.Duration 0x8202b87e0"
|
||||
//!-time
|
||||
}
|
29
vendor/gopl.io/ch12/methods/methods.go
generated
vendored
29
vendor/gopl.io/ch12/methods/methods.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 351.
|
||||
|
||||
// Package methods provides a function to print the methods of any value.
|
||||
package methods
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//!+print
|
||||
// Print prints the method set of the value x.
|
||||
func Print(x interface{}) {
|
||||
v := reflect.ValueOf(x)
|
||||
t := v.Type()
|
||||
fmt.Printf("type %s\n", t)
|
||||
|
||||
for i := 0; i < v.NumMethod(); i++ {
|
||||
methType := v.Method(i).Type()
|
||||
fmt.Printf("func (%s) %s%s\n", t, t.Method(i).Name,
|
||||
strings.TrimPrefix(methType.String(), "func"))
|
||||
}
|
||||
}
|
||||
|
||||
//!-print
|
49
vendor/gopl.io/ch12/methods/methods_test.go
generated
vendored
49
vendor/gopl.io/ch12/methods/methods_test.go
generated
vendored
@ -1,49 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package methods_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gopl.io/ch12/methods"
|
||||
)
|
||||
|
||||
func ExamplePrintDuration() {
|
||||
methods.Print(time.Hour)
|
||||
// Output:
|
||||
// type time.Duration
|
||||
// func (time.Duration) Hours() float64
|
||||
// func (time.Duration) Minutes() float64
|
||||
// func (time.Duration) Nanoseconds() int64
|
||||
// func (time.Duration) Seconds() float64
|
||||
// func (time.Duration) String() string
|
||||
}
|
||||
|
||||
func ExamplePrintReplacer() {
|
||||
methods.Print(new(strings.Replacer))
|
||||
// Output:
|
||||
// type *strings.Replacer
|
||||
// func (*strings.Replacer) Replace(string) string
|
||||
// func (*strings.Replacer) WriteString(io.Writer, string) (int, error)
|
||||
}
|
||||
|
||||
/*
|
||||
//!+output
|
||||
methods.Print(time.Hour)
|
||||
// Output:
|
||||
// type time.Duration
|
||||
// func (time.Duration) Hours() float64
|
||||
// func (time.Duration) Minutes() float64
|
||||
// func (time.Duration) Nanoseconds() int64
|
||||
// func (time.Duration) Seconds() float64
|
||||
// func (time.Duration) String() string
|
||||
|
||||
methods.Print(new(strings.Replacer))
|
||||
// Output:
|
||||
// type *strings.Replacer
|
||||
// func (*strings.Replacer) Replace(string) string
|
||||
// func (*strings.Replacer) WriteString(io.Writer, string) (int, error)
|
||||
//!-output
|
||||
*/
|
90
vendor/gopl.io/ch12/params/params.go
generated
vendored
90
vendor/gopl.io/ch12/params/params.go
generated
vendored
@ -1,90 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 349.
|
||||
|
||||
// Package params provides a reflection-based parser for URL parameters.
|
||||
package params
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//!+Unpack
|
||||
|
||||
// Unpack populates the fields of the struct pointed to by ptr
|
||||
// from the HTTP request parameters in req.
|
||||
func Unpack(req *http.Request, ptr interface{}) error {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Build map of fields keyed by effective name.
|
||||
fields := make(map[string]reflect.Value)
|
||||
v := reflect.ValueOf(ptr).Elem() // the struct variable
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
fieldInfo := v.Type().Field(i) // a reflect.StructField
|
||||
tag := fieldInfo.Tag // a reflect.StructTag
|
||||
name := tag.Get("http")
|
||||
if name == "" {
|
||||
name = strings.ToLower(fieldInfo.Name)
|
||||
}
|
||||
fields[name] = v.Field(i)
|
||||
}
|
||||
|
||||
// Update struct field for each parameter in the request.
|
||||
for name, values := range req.Form {
|
||||
f := fields[name]
|
||||
if !f.IsValid() {
|
||||
continue // ignore unrecognized HTTP parameters
|
||||
}
|
||||
for _, value := range values {
|
||||
if f.Kind() == reflect.Slice {
|
||||
elem := reflect.New(f.Type().Elem()).Elem()
|
||||
if err := populate(elem, value); err != nil {
|
||||
return fmt.Errorf("%s: %v", name, err)
|
||||
}
|
||||
f.Set(reflect.Append(f, elem))
|
||||
} else {
|
||||
if err := populate(f, value); err != nil {
|
||||
return fmt.Errorf("%s: %v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//!-Unpack
|
||||
|
||||
//!+populate
|
||||
func populate(v reflect.Value, value string) error {
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
v.SetString(value)
|
||||
|
||||
case reflect.Int:
|
||||
i, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetInt(i)
|
||||
|
||||
case reflect.Bool:
|
||||
b, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetBool(b)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported kind %s", v.Type())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//!-populate
|
60
vendor/gopl.io/ch12/search/main.go
generated
vendored
60
vendor/gopl.io/ch12/search/main.go
generated
vendored
@ -1,60 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 348.
|
||||
|
||||
// Search is a demo of the params.Unpack function.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
//!+
|
||||
|
||||
import "gopl.io/ch12/params"
|
||||
|
||||
// search implements the /search URL endpoint.
|
||||
func search(resp http.ResponseWriter, req *http.Request) {
|
||||
var data struct {
|
||||
Labels []string `http:"l"`
|
||||
MaxResults int `http:"max"`
|
||||
Exact bool `http:"x"`
|
||||
}
|
||||
data.MaxResults = 10 // set default
|
||||
if err := params.Unpack(req, &data); err != nil {
|
||||
http.Error(resp, err.Error(), http.StatusBadRequest) // 400
|
||||
return
|
||||
}
|
||||
|
||||
// ...rest of handler...
|
||||
fmt.Fprintf(resp, "Search: %+v\n", data)
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/search", search)
|
||||
log.Fatal(http.ListenAndServe(":12345", nil))
|
||||
}
|
||||
|
||||
/*
|
||||
//!+output
|
||||
$ go build gopl.io/ch12/search
|
||||
$ ./search &
|
||||
$ ./fetch 'http://localhost:12345/search'
|
||||
Search: {Labels:[] MaxResults:10 Exact:false}
|
||||
$ ./fetch 'http://localhost:12345/search?l=golang&l=programming'
|
||||
Search: {Labels:[golang programming] MaxResults:10 Exact:false}
|
||||
$ ./fetch 'http://localhost:12345/search?l=golang&l=programming&max=100'
|
||||
Search: {Labels:[golang programming] MaxResults:100 Exact:false}
|
||||
$ ./fetch 'http://localhost:12345/search?x=true&l=golang&l=programming'
|
||||
Search: {Labels:[golang programming] MaxResults:10 Exact:true}
|
||||
$ ./fetch 'http://localhost:12345/search?q=hello&x=123'
|
||||
x: strconv.ParseBool: parsing "123": invalid syntax
|
||||
$ ./fetch 'http://localhost:12345/search?q=hello&max=lots'
|
||||
max: strconv.ParseInt: parsing "lots": invalid syntax
|
||||
//!-output
|
||||
*/
|
162
vendor/gopl.io/ch12/sexpr/decode.go
generated
vendored
162
vendor/gopl.io/ch12/sexpr/decode.go
generated
vendored
@ -1,162 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 344.
|
||||
|
||||
// Package sexpr provides a means for converting Go objects to and
|
||||
// from S-expressions.
|
||||
package sexpr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"text/scanner"
|
||||
)
|
||||
|
||||
//!+Unmarshal
|
||||
// Unmarshal parses S-expression data and populates the variable
|
||||
// whose address is in the non-nil pointer out.
|
||||
func Unmarshal(data []byte, out interface{}) (err error) {
|
||||
lex := &lexer{scan: scanner.Scanner{Mode: scanner.GoTokens}}
|
||||
lex.scan.Init(bytes.NewReader(data))
|
||||
lex.next() // get the first token
|
||||
defer func() {
|
||||
// NOTE: this is not an example of ideal error handling.
|
||||
if x := recover(); x != nil {
|
||||
err = fmt.Errorf("error at %s: %v", lex.scan.Position, x)
|
||||
}
|
||||
}()
|
||||
read(lex, reflect.ValueOf(out).Elem())
|
||||
return nil
|
||||
}
|
||||
|
||||
//!-Unmarshal
|
||||
|
||||
//!+lexer
|
||||
type lexer struct {
|
||||
scan scanner.Scanner
|
||||
token rune // the current token
|
||||
}
|
||||
|
||||
func (lex *lexer) next() { lex.token = lex.scan.Scan() }
|
||||
func (lex *lexer) text() string { return lex.scan.TokenText() }
|
||||
|
||||
func (lex *lexer) consume(want rune) {
|
||||
if lex.token != want { // NOTE: Not an example of good error handling.
|
||||
panic(fmt.Sprintf("got %q, want %q", lex.text(), want))
|
||||
}
|
||||
lex.next()
|
||||
}
|
||||
|
||||
//!-lexer
|
||||
|
||||
// The read function is a decoder for a small subset of well-formed
|
||||
// S-expressions. For brevity of our example, it takes many dubious
|
||||
// shortcuts.
|
||||
//
|
||||
// The parser assumes
|
||||
// - that the S-expression input is well-formed; it does no error checking.
|
||||
// - that the S-expression input corresponds to the type of the variable.
|
||||
// - that all numbers in the input are non-negative decimal integers.
|
||||
// - that all keys in ((key value) ...) struct syntax are unquoted symbols.
|
||||
// - that the input does not contain dotted lists such as (1 2 . 3).
|
||||
// - that the input does not contain Lisp reader macros such 'x and #'x.
|
||||
//
|
||||
// The reflection logic assumes
|
||||
// - that v is always a variable of the appropriate type for the
|
||||
// S-expression value. For example, v must not be a boolean,
|
||||
// interface, channel, or function, and if v is an array, the input
|
||||
// must have the correct number of elements.
|
||||
// - that v in the top-level call to read has the zero value of its
|
||||
// type and doesn't need clearing.
|
||||
// - that if v is a numeric variable, it is a signed integer.
|
||||
|
||||
//!+read
|
||||
func read(lex *lexer, v reflect.Value) {
|
||||
switch lex.token {
|
||||
case scanner.Ident:
|
||||
// The only valid identifiers are
|
||||
// "nil" and struct field names.
|
||||
if lex.text() == "nil" {
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
lex.next()
|
||||
return
|
||||
}
|
||||
case scanner.String:
|
||||
s, _ := strconv.Unquote(lex.text()) // NOTE: ignoring errors
|
||||
v.SetString(s)
|
||||
lex.next()
|
||||
return
|
||||
case scanner.Int:
|
||||
i, _ := strconv.Atoi(lex.text()) // NOTE: ignoring errors
|
||||
v.SetInt(int64(i))
|
||||
lex.next()
|
||||
return
|
||||
case '(':
|
||||
lex.next()
|
||||
readList(lex, v)
|
||||
lex.next() // consume ')'
|
||||
return
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected token %q", lex.text()))
|
||||
}
|
||||
|
||||
//!-read
|
||||
|
||||
//!+readlist
|
||||
func readList(lex *lexer, v reflect.Value) {
|
||||
switch v.Kind() {
|
||||
case reflect.Array: // (item ...)
|
||||
for i := 0; !endList(lex); i++ {
|
||||
read(lex, v.Index(i))
|
||||
}
|
||||
|
||||
case reflect.Slice: // (item ...)
|
||||
for !endList(lex) {
|
||||
item := reflect.New(v.Type().Elem()).Elem()
|
||||
read(lex, item)
|
||||
v.Set(reflect.Append(v, item))
|
||||
}
|
||||
|
||||
case reflect.Struct: // ((name value) ...)
|
||||
for !endList(lex) {
|
||||
lex.consume('(')
|
||||
if lex.token != scanner.Ident {
|
||||
panic(fmt.Sprintf("got token %q, want field name", lex.text()))
|
||||
}
|
||||
name := lex.text()
|
||||
lex.next()
|
||||
read(lex, v.FieldByName(name))
|
||||
lex.consume(')')
|
||||
}
|
||||
|
||||
case reflect.Map: // ((key value) ...)
|
||||
v.Set(reflect.MakeMap(v.Type()))
|
||||
for !endList(lex) {
|
||||
lex.consume('(')
|
||||
key := reflect.New(v.Type().Key()).Elem()
|
||||
read(lex, key)
|
||||
value := reflect.New(v.Type().Elem()).Elem()
|
||||
read(lex, value)
|
||||
v.SetMapIndex(key, value)
|
||||
lex.consume(')')
|
||||
}
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("cannot decode list into %v", v.Type()))
|
||||
}
|
||||
}
|
||||
|
||||
func endList(lex *lexer) bool {
|
||||
switch lex.token {
|
||||
case scanner.EOF:
|
||||
panic("end of file")
|
||||
case ')':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//!-readlist
|
97
vendor/gopl.io/ch12/sexpr/encode.go
generated
vendored
97
vendor/gopl.io/ch12/sexpr/encode.go
generated
vendored
@ -1,97 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 339.
|
||||
|
||||
package sexpr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
//!+Marshal
|
||||
// Marshal encodes a Go value in S-expression form.
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := encode(&buf, reflect.ValueOf(v)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
//!-Marshal
|
||||
|
||||
// encode writes to buf an S-expression representation of v.
|
||||
//!+encode
|
||||
func encode(buf *bytes.Buffer, v reflect.Value) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Invalid:
|
||||
buf.WriteString("nil")
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16,
|
||||
reflect.Int32, reflect.Int64:
|
||||
fmt.Fprintf(buf, "%d", v.Int())
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16,
|
||||
reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
fmt.Fprintf(buf, "%d", v.Uint())
|
||||
|
||||
case reflect.String:
|
||||
fmt.Fprintf(buf, "%q", v.String())
|
||||
|
||||
case reflect.Ptr:
|
||||
return encode(buf, v.Elem())
|
||||
|
||||
case reflect.Array, reflect.Slice: // (value ...)
|
||||
buf.WriteByte('(')
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if i > 0 {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
if err := encode(buf, v.Index(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
|
||||
case reflect.Struct: // ((name value) ...)
|
||||
buf.WriteByte('(')
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if i > 0 {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
fmt.Fprintf(buf, "(%s ", v.Type().Field(i).Name)
|
||||
if err := encode(buf, v.Field(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
|
||||
case reflect.Map: // ((key value) ...)
|
||||
buf.WriteByte('(')
|
||||
for i, key := range v.MapKeys() {
|
||||
if i > 0 {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
buf.WriteByte('(')
|
||||
if err := encode(buf, key); err != nil {
|
||||
return err
|
||||
}
|
||||
buf.WriteByte(' ')
|
||||
if err := encode(buf, v.MapIndex(key)); err != nil {
|
||||
return err
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
|
||||
default: // float, complex, bool, chan, func, interface
|
||||
return fmt.Errorf("unsupported type: %s", v.Type())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//!-encode
|
183
vendor/gopl.io/ch12/sexpr/pretty.go
generated
vendored
183
vendor/gopl.io/ch12/sexpr/pretty.go
generated
vendored
@ -1,183 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package sexpr
|
||||
|
||||
// This file implements the algorithm described in Derek C. Oppen's
|
||||
// 1979 Stanford technical report, "Pretty Printing".
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func MarshalIndent(v interface{}) ([]byte, error) {
|
||||
p := printer{width: margin}
|
||||
if err := pretty(&p, reflect.ValueOf(v)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.Bytes(), nil
|
||||
}
|
||||
|
||||
const margin = 80
|
||||
|
||||
type token struct {
|
||||
kind rune // one of "s ()" (string, blank, start, end)
|
||||
str string
|
||||
size int
|
||||
}
|
||||
|
||||
type printer struct {
|
||||
tokens []*token // FIFO buffer
|
||||
stack []*token // stack of open ' ' and '(' tokens
|
||||
rtotal int // total number of spaces needed to print stream
|
||||
|
||||
bytes.Buffer
|
||||
indents []int
|
||||
width int // remaining space
|
||||
}
|
||||
|
||||
func (p *printer) string(str string) {
|
||||
tok := &token{kind: 's', str: str, size: len(str)}
|
||||
if len(p.stack) == 0 {
|
||||
p.print(tok)
|
||||
} else {
|
||||
p.tokens = append(p.tokens, tok)
|
||||
p.rtotal += len(str)
|
||||
}
|
||||
}
|
||||
func (p *printer) pop() (top *token) {
|
||||
last := len(p.stack) - 1
|
||||
top, p.stack = p.stack[last], p.stack[:last]
|
||||
return
|
||||
}
|
||||
func (p *printer) begin() {
|
||||
if len(p.stack) == 0 {
|
||||
p.rtotal = 1
|
||||
}
|
||||
t := &token{kind: '(', size: -p.rtotal}
|
||||
p.tokens = append(p.tokens, t)
|
||||
p.stack = append(p.stack, t) // push
|
||||
p.string("(")
|
||||
}
|
||||
func (p *printer) end() {
|
||||
p.string(")")
|
||||
p.tokens = append(p.tokens, &token{kind: ')'})
|
||||
x := p.pop()
|
||||
x.size += p.rtotal
|
||||
if x.kind == ' ' {
|
||||
p.pop().size += p.rtotal
|
||||
}
|
||||
if len(p.stack) == 0 {
|
||||
for _, tok := range p.tokens {
|
||||
p.print(tok)
|
||||
}
|
||||
p.tokens = nil
|
||||
}
|
||||
}
|
||||
func (p *printer) space() {
|
||||
last := len(p.stack) - 1
|
||||
x := p.stack[last]
|
||||
if x.kind == ' ' {
|
||||
x.size += p.rtotal
|
||||
p.stack = p.stack[:last] // pop
|
||||
}
|
||||
t := &token{kind: ' ', size: -p.rtotal}
|
||||
p.tokens = append(p.tokens, t)
|
||||
p.stack = append(p.stack, t)
|
||||
p.rtotal++
|
||||
}
|
||||
func (p *printer) print(t *token) {
|
||||
switch t.kind {
|
||||
case 's':
|
||||
p.WriteString(t.str)
|
||||
p.width -= len(t.str)
|
||||
case '(':
|
||||
p.indents = append(p.indents, p.width)
|
||||
case ')':
|
||||
p.indents = p.indents[:len(p.indents)-1] // pop
|
||||
case ' ':
|
||||
if t.size > p.width {
|
||||
p.width = p.indents[len(p.indents)-1] - 1
|
||||
fmt.Fprintf(&p.Buffer, "\n%*s", margin-p.width, "")
|
||||
} else {
|
||||
p.WriteByte(' ')
|
||||
p.width--
|
||||
}
|
||||
}
|
||||
}
|
||||
func (p *printer) stringf(format string, args ...interface{}) {
|
||||
p.string(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func pretty(p *printer, v reflect.Value) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Invalid:
|
||||
p.string("nil")
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16,
|
||||
reflect.Int32, reflect.Int64:
|
||||
p.stringf("%d", v.Int())
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16,
|
||||
reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
p.stringf("%d", v.Uint())
|
||||
|
||||
case reflect.String:
|
||||
p.stringf("%q", v.String())
|
||||
|
||||
case reflect.Array, reflect.Slice: // (value ...)
|
||||
p.begin()
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if i > 0 {
|
||||
p.space()
|
||||
}
|
||||
if err := pretty(p, v.Index(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
p.end()
|
||||
|
||||
case reflect.Struct: // ((name value ...)
|
||||
p.begin()
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if i > 0 {
|
||||
p.space()
|
||||
}
|
||||
p.begin()
|
||||
p.string(v.Type().Field(i).Name)
|
||||
p.space()
|
||||
if err := pretty(p, v.Field(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
p.end()
|
||||
}
|
||||
p.end()
|
||||
|
||||
case reflect.Map: // ((key value ...)
|
||||
p.begin()
|
||||
for i, key := range v.MapKeys() {
|
||||
if i > 0 {
|
||||
p.space()
|
||||
}
|
||||
p.begin()
|
||||
if err := pretty(p, key); err != nil {
|
||||
return err
|
||||
}
|
||||
p.space()
|
||||
if err := pretty(p, v.MapIndex(key)); err != nil {
|
||||
return err
|
||||
}
|
||||
p.end()
|
||||
}
|
||||
p.end()
|
||||
|
||||
case reflect.Ptr:
|
||||
return pretty(p, v.Elem())
|
||||
|
||||
default: // float, complex, bool, chan, func, interface
|
||||
return fmt.Errorf("unsupported type: %s", v.Type())
|
||||
}
|
||||
return nil
|
||||
}
|
74
vendor/gopl.io/ch12/sexpr/sexpr_test.go
generated
vendored
74
vendor/gopl.io/ch12/sexpr/sexpr_test.go
generated
vendored
@ -1,74 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package sexpr
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Test verifies that encoding and decoding a complex data value
|
||||
// produces an equal result.
|
||||
//
|
||||
// The test does not make direct assertions about the encoded output
|
||||
// because the output depends on map iteration order, which is
|
||||
// nondeterministic. The output of the t.Log statements can be
|
||||
// inspected by running the test with the -v flag:
|
||||
//
|
||||
// $ go test -v gopl.io/ch12/sexpr
|
||||
//
|
||||
func Test(t *testing.T) {
|
||||
type Movie struct {
|
||||
Title, Subtitle string
|
||||
Year int
|
||||
Actor map[string]string
|
||||
Oscars []string
|
||||
Sequel *string
|
||||
}
|
||||
strangelove := Movie{
|
||||
Title: "Dr. Strangelove",
|
||||
Subtitle: "How I Learned to Stop Worrying and Love the Bomb",
|
||||
Year: 1964,
|
||||
Actor: map[string]string{
|
||||
"Dr. Strangelove": "Peter Sellers",
|
||||
"Grp. Capt. Lionel Mandrake": "Peter Sellers",
|
||||
"Pres. Merkin Muffley": "Peter Sellers",
|
||||
"Gen. Buck Turgidson": "George C. Scott",
|
||||
"Brig. Gen. Jack D. Ripper": "Sterling Hayden",
|
||||
`Maj. T.J. "King" Kong`: "Slim Pickens",
|
||||
},
|
||||
Oscars: []string{
|
||||
"Best Actor (Nomin.)",
|
||||
"Best Adapted Screenplay (Nomin.)",
|
||||
"Best Director (Nomin.)",
|
||||
"Best Picture (Nomin.)",
|
||||
},
|
||||
}
|
||||
|
||||
// Encode it
|
||||
data, err := Marshal(strangelove)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal failed: %v", err)
|
||||
}
|
||||
t.Logf("Marshal() = %s\n", data)
|
||||
|
||||
// Decode it
|
||||
var movie Movie
|
||||
if err := Unmarshal(data, &movie); err != nil {
|
||||
t.Fatalf("Unmarshal failed: %v", err)
|
||||
}
|
||||
t.Logf("Unmarshal() = %+v\n", movie)
|
||||
|
||||
// Check equality.
|
||||
if !reflect.DeepEqual(movie, strangelove) {
|
||||
t.Fatal("not equal")
|
||||
}
|
||||
|
||||
// Pretty-print it:
|
||||
data, err = MarshalIndent(strangelove)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("MarshalIdent() = %s\n", data)
|
||||
}
|
28
vendor/gopl.io/ch13/bzip-print/bzip2.c
generated
vendored
28
vendor/gopl.io/ch13/bzip-print/bzip2.c
generated
vendored
@ -1,28 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 362.
|
||||
// This is the version that appears in print,
|
||||
// but it does not comply with the proposed
|
||||
// rules for passing pointers between Go and C.
|
||||
// (https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md)
|
||||
// See gopl.io/ch13/bzip for an updated version.
|
||||
|
||||
//!+
|
||||
/* This file is gopl.io/ch13/bzip/bzip2.c, */
|
||||
/* a simple wrapper for libbzip2 suitable for cgo. */
|
||||
#include <bzlib.h>
|
||||
|
||||
int bz2compress(bz_stream *s, int action,
|
||||
char *in, unsigned *inlen, char *out, unsigned *outlen) {
|
||||
s->next_in = in;
|
||||
s->avail_in = *inlen;
|
||||
s->next_out = out;
|
||||
s->avail_out = *outlen;
|
||||
int r = BZ2_bzCompress(s, action);
|
||||
*inlen -= s->avail_in;
|
||||
*outlen -= s->avail_out;
|
||||
return r;
|
||||
}
|
||||
|
||||
//!-
|
96
vendor/gopl.io/ch13/bzip-print/bzip2.go
generated
vendored
96
vendor/gopl.io/ch13/bzip-print/bzip2.go
generated
vendored
@ -1,96 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 362.
|
||||
// This is the version that appears in print,
|
||||
// but it does not comply with the proposed
|
||||
// rules for passing pointers between Go and C.
|
||||
// (https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md)
|
||||
// See gopl.io/ch13/bzip for an updated version.
|
||||
//!+
|
||||
|
||||
// Package bzip provides a writer that uses bzip2 compression (bzip.org).
|
||||
package bzip
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I/usr/include
|
||||
#cgo LDFLAGS: -L/usr/lib -lbz2
|
||||
#include <bzlib.h>
|
||||
int bz2compress(bz_stream *s, int action,
|
||||
char *in, unsigned *inlen, char *out, unsigned *outlen);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type writer struct {
|
||||
w io.Writer // underlying output stream
|
||||
stream *C.bz_stream
|
||||
outbuf [64 * 1024]byte
|
||||
}
|
||||
|
||||
// NewWriter returns a writer for bzip2-compressed streams.
|
||||
func NewWriter(out io.Writer) io.WriteCloser {
|
||||
const (
|
||||
blockSize = 9
|
||||
verbosity = 0
|
||||
workFactor = 30
|
||||
)
|
||||
w := &writer{w: out, stream: new(C.bz_stream)}
|
||||
C.BZ2_bzCompressInit(w.stream, blockSize, verbosity, workFactor)
|
||||
return w
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
//!+write
|
||||
func (w *writer) Write(data []byte) (int, error) {
|
||||
if w.stream == nil {
|
||||
panic("closed")
|
||||
}
|
||||
var total int // uncompressed bytes written
|
||||
|
||||
for len(data) > 0 {
|
||||
inlen, outlen := C.uint(len(data)), C.uint(cap(w.outbuf))
|
||||
C.bz2compress(w.stream, C.BZ_RUN,
|
||||
(*C.char)(unsafe.Pointer(&data[0])), &inlen,
|
||||
(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
|
||||
total += int(inlen)
|
||||
data = data[inlen:]
|
||||
if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
|
||||
return total, err
|
||||
}
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
//!-write
|
||||
|
||||
//!+close
|
||||
// Close flushes the compressed data and closes the stream.
|
||||
// It does not close the underlying io.Writer.
|
||||
func (w *writer) Close() error {
|
||||
if w.stream == nil {
|
||||
panic("closed")
|
||||
}
|
||||
defer func() {
|
||||
C.BZ2_bzCompressEnd(w.stream)
|
||||
w.stream = nil
|
||||
}()
|
||||
for {
|
||||
inlen, outlen := C.uint(0), C.uint(cap(w.outbuf))
|
||||
r := C.bz2compress(w.stream, C.BZ_FINISH, nil, &inlen,
|
||||
(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
|
||||
if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
|
||||
return err
|
||||
}
|
||||
if r == C.BZ_STREAM_END {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-close
|
40
vendor/gopl.io/ch13/bzip-print/bzip2_test.go
generated
vendored
40
vendor/gopl.io/ch13/bzip-print/bzip2_test.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package bzip_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/bzip2" // reader
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"gopl.io/ch13/bzip" // writer
|
||||
)
|
||||
|
||||
func TestBzip2(t *testing.T) {
|
||||
var compressed, uncompressed bytes.Buffer
|
||||
w := bzip.NewWriter(&compressed)
|
||||
|
||||
// Write a repetitive message in a million pieces,
|
||||
// compressing one copy but not the other.
|
||||
tee := io.MultiWriter(w, &uncompressed)
|
||||
for i := 0; i < 1000000; i++ {
|
||||
io.WriteString(tee, "hello")
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check the size of the compressed stream.
|
||||
if got, want := compressed.Len(), 255; got != want {
|
||||
t.Errorf("1 million hellos compressed to %d bytes, want %d", got, want)
|
||||
}
|
||||
|
||||
// Decompress and compare with original.
|
||||
var decompressed bytes.Buffer
|
||||
io.Copy(&decompressed, bzip2.NewReader(&compressed))
|
||||
if !bytes.Equal(uncompressed.Bytes(), decompressed.Bytes()) {
|
||||
t.Error("decompression yielded a different message")
|
||||
}
|
||||
}
|
32
vendor/gopl.io/ch13/bzip/bzip2.c
generated
vendored
32
vendor/gopl.io/ch13/bzip/bzip2.c
generated
vendored
@ -1,32 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 362.
|
||||
//
|
||||
// The version of this program that appeared in the first and second
|
||||
// printings did not comply with the proposed rules for passing
|
||||
// pointers between Go and C, described here:
|
||||
// https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md
|
||||
//
|
||||
// The version below, which appears in the third printing,
|
||||
// has been corrected. See bzip2.go for explanation.
|
||||
|
||||
//!+
|
||||
/* This file is gopl.io/ch13/bzip/bzip2.c, */
|
||||
/* a simple wrapper for libbzip2 suitable for cgo. */
|
||||
#include <bzlib.h>
|
||||
|
||||
int bz2compress(bz_stream *s, int action,
|
||||
char *in, unsigned *inlen, char *out, unsigned *outlen) {
|
||||
s->next_in = in;
|
||||
s->avail_in = *inlen;
|
||||
s->next_out = out;
|
||||
s->avail_out = *outlen;
|
||||
int r = BZ2_bzCompress(s, action);
|
||||
*inlen -= s->avail_in;
|
||||
*outlen -= s->avail_out;
|
||||
s->next_in = s->next_out = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
//!-
|
111
vendor/gopl.io/ch13/bzip/bzip2.go
generated
vendored
111
vendor/gopl.io/ch13/bzip/bzip2.go
generated
vendored
@ -1,111 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 362.
|
||||
//
|
||||
// The version of this program that appeared in the first and second
|
||||
// printings did not comply with the proposed rules for passing
|
||||
// pointers between Go and C, described here:
|
||||
// https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md
|
||||
//
|
||||
// The rules forbid a C function like bz2compress from storing 'in'
|
||||
// and 'out' (pointers to variables allocated by Go) into the Go
|
||||
// variable 's', even temporarily.
|
||||
//
|
||||
// The version below, which appears in the third printing, has been
|
||||
// corrected. To comply with the rules, the bz_stream variable must
|
||||
// be allocated by C code. We have introduced two C functions,
|
||||
// bz2alloc and bz2free, to allocate and free instances of the
|
||||
// bz_stream type. Also, we have changed bz2compress so that before
|
||||
// it returns, it clears the fields of the bz_stream that contain
|
||||
// pointers to Go variables.
|
||||
|
||||
//!+
|
||||
|
||||
// Package bzip provides a writer that uses bzip2 compression (bzip.org).
|
||||
package bzip
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I/usr/include
|
||||
#cgo LDFLAGS: -L/usr/lib -lbz2
|
||||
#include <bzlib.h>
|
||||
#include <stdlib.h>
|
||||
bz_stream* bz2alloc() { return calloc(1, sizeof(bz_stream)); }
|
||||
int bz2compress(bz_stream *s, int action,
|
||||
char *in, unsigned *inlen, char *out, unsigned *outlen);
|
||||
void bz2free(bz_stream* s) { free(s); }
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type writer struct {
|
||||
w io.Writer // underlying output stream
|
||||
stream *C.bz_stream
|
||||
outbuf [64 * 1024]byte
|
||||
}
|
||||
|
||||
// NewWriter returns a writer for bzip2-compressed streams.
|
||||
func NewWriter(out io.Writer) io.WriteCloser {
|
||||
const blockSize = 9
|
||||
const verbosity = 0
|
||||
const workFactor = 30
|
||||
w := &writer{w: out, stream: C.bz2alloc()}
|
||||
C.BZ2_bzCompressInit(w.stream, blockSize, verbosity, workFactor)
|
||||
return w
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
//!+write
|
||||
func (w *writer) Write(data []byte) (int, error) {
|
||||
if w.stream == nil {
|
||||
panic("closed")
|
||||
}
|
||||
var total int // uncompressed bytes written
|
||||
|
||||
for len(data) > 0 {
|
||||
inlen, outlen := C.uint(len(data)), C.uint(cap(w.outbuf))
|
||||
C.bz2compress(w.stream, C.BZ_RUN,
|
||||
(*C.char)(unsafe.Pointer(&data[0])), &inlen,
|
||||
(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
|
||||
total += int(inlen)
|
||||
data = data[inlen:]
|
||||
if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
|
||||
return total, err
|
||||
}
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
//!-write
|
||||
|
||||
//!+close
|
||||
// Close flushes the compressed data and closes the stream.
|
||||
// It does not close the underlying io.Writer.
|
||||
func (w *writer) Close() error {
|
||||
if w.stream == nil {
|
||||
panic("closed")
|
||||
}
|
||||
defer func() {
|
||||
C.BZ2_bzCompressEnd(w.stream)
|
||||
C.bz2free(w.stream)
|
||||
w.stream = nil
|
||||
}()
|
||||
for {
|
||||
inlen, outlen := C.uint(0), C.uint(cap(w.outbuf))
|
||||
r := C.bz2compress(w.stream, C.BZ_FINISH, nil, &inlen,
|
||||
(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
|
||||
if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
|
||||
return err
|
||||
}
|
||||
if r == C.BZ_STREAM_END {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-close
|
40
vendor/gopl.io/ch13/bzip/bzip2_test.go
generated
vendored
40
vendor/gopl.io/ch13/bzip/bzip2_test.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package bzip_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/bzip2" // reader
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"gopl.io/ch13/bzip" // writer
|
||||
)
|
||||
|
||||
func TestBzip2(t *testing.T) {
|
||||
var compressed, uncompressed bytes.Buffer
|
||||
w := bzip.NewWriter(&compressed)
|
||||
|
||||
// Write a repetitive message in a million pieces,
|
||||
// compressing one copy but not the other.
|
||||
tee := io.MultiWriter(w, &uncompressed)
|
||||
for i := 0; i < 1000000; i++ {
|
||||
io.WriteString(tee, "hello")
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check the size of the compressed stream.
|
||||
if got, want := compressed.Len(), 255; got != want {
|
||||
t.Errorf("1 million hellos compressed to %d bytes, want %d", got, want)
|
||||
}
|
||||
|
||||
// Decompress and compare with original.
|
||||
var decompressed bytes.Buffer
|
||||
io.Copy(&decompressed, bzip2.NewReader(&compressed))
|
||||
if !bytes.Equal(uncompressed.Bytes(), decompressed.Bytes()) {
|
||||
t.Error("decompression yielded a different message")
|
||||
}
|
||||
}
|
29
vendor/gopl.io/ch13/bzipper/main.go
generated
vendored
29
vendor/gopl.io/ch13/bzipper/main.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 365.
|
||||
|
||||
//!+
|
||||
|
||||
// Bzipper reads input, bzip2-compresses it, and writes it out.
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"gopl.io/ch13/bzip"
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := bzip.NewWriter(os.Stdout)
|
||||
if _, err := io.Copy(w, os.Stdin); err != nil {
|
||||
log.Fatalf("bzipper: %v\n", err)
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
log.Fatalf("bzipper: close: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
127
vendor/gopl.io/ch13/equal/equal.go
generated
vendored
127
vendor/gopl.io/ch13/equal/equal.go
generated
vendored
@ -1,127 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 359.
|
||||
|
||||
// Package equal provides a deep equivalence relation for arbitrary values.
|
||||
package equal
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//!+
|
||||
func equal(x, y reflect.Value, seen map[comparison]bool) bool {
|
||||
if !x.IsValid() || !y.IsValid() {
|
||||
return x.IsValid() == y.IsValid()
|
||||
}
|
||||
if x.Type() != y.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
// ...cycle check omitted (shown later)...
|
||||
|
||||
//!-
|
||||
//!+cyclecheck
|
||||
// cycle check
|
||||
if x.CanAddr() && y.CanAddr() {
|
||||
xptr := unsafe.Pointer(x.UnsafeAddr())
|
||||
yptr := unsafe.Pointer(y.UnsafeAddr())
|
||||
if xptr == yptr {
|
||||
return true // identical references
|
||||
}
|
||||
c := comparison{xptr, yptr, x.Type()}
|
||||
if seen[c] {
|
||||
return true // already seen
|
||||
}
|
||||
seen[c] = true
|
||||
}
|
||||
//!-cyclecheck
|
||||
//!+
|
||||
switch x.Kind() {
|
||||
case reflect.Bool:
|
||||
return x.Bool() == y.Bool()
|
||||
|
||||
case reflect.String:
|
||||
return x.String() == y.String()
|
||||
|
||||
// ...numeric cases omitted for brevity...
|
||||
|
||||
//!-
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64:
|
||||
return x.Int() == y.Int()
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
||||
reflect.Uint64, reflect.Uintptr:
|
||||
return x.Uint() == y.Uint()
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return x.Float() == y.Float()
|
||||
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return x.Complex() == y.Complex()
|
||||
//!+
|
||||
case reflect.Chan, reflect.UnsafePointer, reflect.Func:
|
||||
return x.Pointer() == y.Pointer()
|
||||
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
return equal(x.Elem(), y.Elem(), seen)
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
if x.Len() != y.Len() {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < x.Len(); i++ {
|
||||
if !equal(x.Index(i), y.Index(i), seen) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
// ...struct and map cases omitted for brevity...
|
||||
//!-
|
||||
case reflect.Struct:
|
||||
for i, n := 0, x.NumField(); i < n; i++ {
|
||||
if !equal(x.Field(i), y.Field(i), seen) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case reflect.Map:
|
||||
if x.Len() != y.Len() {
|
||||
return false
|
||||
}
|
||||
for _, k := range x.MapKeys() {
|
||||
if !equal(x.MapIndex(k), y.MapIndex(k), seen) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
//!+
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
//!+comparison
|
||||
// Equal reports whether x and y are deeply equal.
|
||||
//!-comparison
|
||||
//
|
||||
// Map keys are always compared with ==, not deeply.
|
||||
// (This matters for keys containing pointers or interfaces.)
|
||||
//!+comparison
|
||||
func Equal(x, y interface{}) bool {
|
||||
seen := make(map[comparison]bool)
|
||||
return equal(reflect.ValueOf(x), reflect.ValueOf(y), seen)
|
||||
}
|
||||
|
||||
type comparison struct {
|
||||
x, y unsafe.Pointer
|
||||
t reflect.Type
|
||||
}
|
||||
|
||||
//!-comparison
|
133
vendor/gopl.io/ch13/equal/equal_test.go
generated
vendored
133
vendor/gopl.io/ch13/equal/equal_test.go
generated
vendored
@ -1,133 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package equal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
one, oneAgain, two := 1, 1, 2
|
||||
|
||||
type CyclePtr *CyclePtr
|
||||
var cyclePtr1, cyclePtr2 CyclePtr
|
||||
cyclePtr1 = &cyclePtr1
|
||||
cyclePtr2 = &cyclePtr2
|
||||
|
||||
type CycleSlice []CycleSlice
|
||||
var cycleSlice CycleSlice
|
||||
cycleSlice = append(cycleSlice, cycleSlice)
|
||||
|
||||
ch1, ch2 := make(chan int), make(chan int)
|
||||
var ch1ro <-chan int = ch1
|
||||
|
||||
type mystring string
|
||||
|
||||
var iface1, iface1Again, iface2 interface{} = &one, &oneAgain, &two
|
||||
|
||||
for _, test := range []struct {
|
||||
x, y interface{}
|
||||
want bool
|
||||
}{
|
||||
// basic types
|
||||
{1, 1, true},
|
||||
{1, 2, false}, // different values
|
||||
{1, 1.0, false}, // different types
|
||||
{"foo", "foo", true},
|
||||
{"foo", "bar", false},
|
||||
{mystring("foo"), "foo", false}, // different types
|
||||
// slices
|
||||
{[]string{"foo"}, []string{"foo"}, true},
|
||||
{[]string{"foo"}, []string{"bar"}, false},
|
||||
{[]string{}, []string(nil), true},
|
||||
// slice cycles
|
||||
{cycleSlice, cycleSlice, true},
|
||||
// maps
|
||||
{
|
||||
map[string][]int{"foo": {1, 2, 3}},
|
||||
map[string][]int{"foo": {1, 2, 3}},
|
||||
true,
|
||||
},
|
||||
{
|
||||
map[string][]int{"foo": {1, 2, 3}},
|
||||
map[string][]int{"foo": {1, 2, 3, 4}},
|
||||
false,
|
||||
},
|
||||
{
|
||||
map[string][]int{},
|
||||
map[string][]int(nil),
|
||||
true,
|
||||
},
|
||||
// pointers
|
||||
{&one, &one, true},
|
||||
{&one, &two, false},
|
||||
{&one, &oneAgain, true},
|
||||
{new(bytes.Buffer), new(bytes.Buffer), true},
|
||||
// pointer cycles
|
||||
{cyclePtr1, cyclePtr1, true},
|
||||
{cyclePtr2, cyclePtr2, true},
|
||||
{cyclePtr1, cyclePtr2, true}, // they're deeply equal
|
||||
// functions
|
||||
{(func())(nil), (func())(nil), true},
|
||||
{(func())(nil), func() {}, false},
|
||||
{func() {}, func() {}, false},
|
||||
// arrays
|
||||
{[...]int{1, 2, 3}, [...]int{1, 2, 3}, true},
|
||||
{[...]int{1, 2, 3}, [...]int{1, 2, 4}, false},
|
||||
// channels
|
||||
{ch1, ch1, true},
|
||||
{ch1, ch2, false},
|
||||
{ch1ro, ch1, false}, // NOTE: not equal
|
||||
// interfaces
|
||||
{&iface1, &iface1, true},
|
||||
{&iface1, &iface2, false},
|
||||
{&iface1Again, &iface1, true},
|
||||
} {
|
||||
if Equal(test.x, test.y) != test.want {
|
||||
t.Errorf("Equal(%v, %v) = %t",
|
||||
test.x, test.y, !test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Example_equal() {
|
||||
//!+
|
||||
fmt.Println(Equal([]int{1, 2, 3}, []int{1, 2, 3})) // "true"
|
||||
fmt.Println(Equal([]string{"foo"}, []string{"bar"})) // "false"
|
||||
fmt.Println(Equal([]string(nil), []string{})) // "true"
|
||||
fmt.Println(Equal(map[string]int(nil), map[string]int{})) // "true"
|
||||
//!-
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func Example_equalCycle() {
|
||||
//!+cycle
|
||||
// Circular linked lists a -> b -> a and c -> c.
|
||||
type link struct {
|
||||
value string
|
||||
tail *link
|
||||
}
|
||||
a, b, c := &link{value: "a"}, &link{value: "b"}, &link{value: "c"}
|
||||
a.tail, b.tail, c.tail = b, a, c
|
||||
fmt.Println(Equal(a, a)) // "true"
|
||||
fmt.Println(Equal(b, b)) // "true"
|
||||
fmt.Println(Equal(c, c)) // "true"
|
||||
fmt.Println(Equal(a, b)) // "false"
|
||||
fmt.Println(Equal(a, c)) // "false"
|
||||
//!-cycle
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
38
vendor/gopl.io/ch13/unsafeptr/main.go
generated
vendored
38
vendor/gopl.io/ch13/unsafeptr/main.go
generated
vendored
@ -1,38 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 357.
|
||||
|
||||
// Package unsafeptr demonstrates basic use of unsafe.Pointer.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//!+main
|
||||
var x struct {
|
||||
a bool
|
||||
b int16
|
||||
c []int
|
||||
}
|
||||
|
||||
// equivalent to pb := &x.b
|
||||
pb := (*int16)(unsafe.Pointer(
|
||||
uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)))
|
||||
*pb = 42
|
||||
|
||||
fmt.Println(x.b) // "42"
|
||||
//!-main
|
||||
}
|
||||
|
||||
/*
|
||||
//!+wrong
|
||||
// NOTE: subtly incorrect!
|
||||
tmp := uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)
|
||||
pb := (*int16)(unsafe.Pointer(tmp))
|
||||
*pb = 42
|
||||
//!-wrong
|
||||
*/
|
22
vendor/gopl.io/ch2/boiling/main.go
generated
vendored
22
vendor/gopl.io/ch2/boiling/main.go
generated
vendored
@ -1,22 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 29.
|
||||
//!+
|
||||
|
||||
// Boiling prints the boiling point of water.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
const boilingF = 212.0
|
||||
|
||||
func main() {
|
||||
var f = boilingF
|
||||
var c = (f - 32) * 5 / 9
|
||||
fmt.Printf("boiling point = %g°F or %g°C\n", f, c)
|
||||
// Output:
|
||||
// boiling point = 212°F or 100°C
|
||||
}
|
||||
|
||||
//!-
|
32
vendor/gopl.io/ch2/cf/main.go
generated
vendored
32
vendor/gopl.io/ch2/cf/main.go
generated
vendored
@ -1,32 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 43.
|
||||
//!+
|
||||
|
||||
// Cf converts its numeric argument to Celsius and Fahrenheit.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"gopl.io/ch2/tempconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for _, arg := range os.Args[1:] {
|
||||
t, err := strconv.ParseFloat(arg, 64)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "cf: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
f := tempconv.Fahrenheit(t)
|
||||
c := tempconv.Celsius(t)
|
||||
fmt.Printf("%s = %s, %s = %s\n",
|
||||
f, tempconv.FToC(f), c, tempconv.CToF(c))
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
27
vendor/gopl.io/ch2/echo4/main.go
generated
vendored
27
vendor/gopl.io/ch2/echo4/main.go
generated
vendored
@ -1,27 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 33.
|
||||
//!+
|
||||
|
||||
// Echo4 prints its command-line arguments.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var n = flag.Bool("n", false, "omit trailing newline")
|
||||
var sep = flag.String("s", " ", "separator")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
fmt.Print(strings.Join(flag.Args(), *sep))
|
||||
if !*n {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
22
vendor/gopl.io/ch2/ftoc/main.go
generated
vendored
22
vendor/gopl.io/ch2/ftoc/main.go
generated
vendored
@ -1,22 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 29.
|
||||
//!+
|
||||
|
||||
// Ftoc prints two Fahrenheit-to-Celsius conversions.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
const freezingF, boilingF = 32.0, 212.0
|
||||
fmt.Printf("%g°F = %g°C\n", freezingF, fToC(freezingF)) // "32°F = 0°C"
|
||||
fmt.Printf("%g°F = %g°C\n", boilingF, fToC(boilingF)) // "212°F = 100°C"
|
||||
}
|
||||
|
||||
func fToC(f float64) float64 {
|
||||
return (f - 32) * 5 / 9
|
||||
}
|
||||
|
||||
//!-
|
31
vendor/gopl.io/ch2/popcount/main.go
generated
vendored
31
vendor/gopl.io/ch2/popcount/main.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 45.
|
||||
|
||||
// (Package doc comment intentionally malformed to demonstrate golint.)
|
||||
//!+
|
||||
package popcount
|
||||
|
||||
// pc[i] is the population count of i.
|
||||
var pc [256]byte
|
||||
|
||||
func init() {
|
||||
for i := range pc {
|
||||
pc[i] = pc[i/2] + byte(i&1)
|
||||
}
|
||||
}
|
||||
|
||||
// PopCount returns the population count (number of set bits) of x.
|
||||
func PopCount(x uint64) int {
|
||||
return int(pc[byte(x>>(0*8))] +
|
||||
pc[byte(x>>(1*8))] +
|
||||
pc[byte(x>>(2*8))] +
|
||||
pc[byte(x>>(3*8))] +
|
||||
pc[byte(x>>(4*8))] +
|
||||
pc[byte(x>>(5*8))] +
|
||||
pc[byte(x>>(6*8))] +
|
||||
pc[byte(x>>(7*8))])
|
||||
}
|
||||
|
||||
//!-
|
83
vendor/gopl.io/ch2/popcount/popcount_test.go
generated
vendored
83
vendor/gopl.io/ch2/popcount/popcount_test.go
generated
vendored
@ -1,83 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package popcount_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gopl.io/ch2/popcount"
|
||||
)
|
||||
|
||||
// -- Alternative implementations --
|
||||
|
||||
func BitCount(x uint64) int {
|
||||
// Hacker's Delight, Figure 5-2.
|
||||
x = x - ((x >> 1) & 0x5555555555555555)
|
||||
x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333)
|
||||
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f
|
||||
x = x + (x >> 8)
|
||||
x = x + (x >> 16)
|
||||
x = x + (x >> 32)
|
||||
return int(x & 0x7f)
|
||||
}
|
||||
|
||||
func PopCountByClearing(x uint64) int {
|
||||
n := 0
|
||||
for x != 0 {
|
||||
x = x & (x - 1) // clear rightmost non-zero bit
|
||||
n++
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func PopCountByShifting(x uint64) int {
|
||||
n := 0
|
||||
for i := uint(0); i < 64; i++ {
|
||||
if x&(1<<i) != 0 {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// -- Benchmarks --
|
||||
|
||||
func BenchmarkPopCount(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
popcount.PopCount(0x1234567890ABCDEF)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBitCount(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
BitCount(0x1234567890ABCDEF)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPopCountByClearing(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
PopCountByClearing(0x1234567890ABCDEF)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPopCountByShifting(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
PopCountByShifting(0x1234567890ABCDEF)
|
||||
}
|
||||
}
|
||||
|
||||
// 2.67GHz Xeon
|
||||
// $ go test -cpu=4 -bench=. gopl.io/ch2/popcount
|
||||
// BenchmarkPopCount-4 200000000 6.30 ns/op
|
||||
// BenchmarkBitCount-4 300000000 4.15 ns/op
|
||||
// BenchmarkPopCountByClearing-4 30000000 45.2 ns/op
|
||||
// BenchmarkPopCountByShifting-4 10000000 153 ns/op
|
||||
//
|
||||
// 2.5GHz Intel Core i5
|
||||
// $ go test -cpu=4 -bench=. gopl.io/ch2/popcount
|
||||
// testing: warning: no tests to run
|
||||
// BenchmarkPopCount-4 200000000 7.52 ns/op
|
||||
// BenchmarkBitCount-4 500000000 3.36 ns/op
|
||||
// BenchmarkPopCountByClearing-4 50000000 34.3 ns/op
|
||||
// BenchmarkPopCountByShifting-4 20000000 108 ns/op
|
16
vendor/gopl.io/ch2/tempconv/conv.go
generated
vendored
16
vendor/gopl.io/ch2/tempconv/conv.go
generated
vendored
@ -1,16 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 41.
|
||||
|
||||
//!+
|
||||
|
||||
package tempconv
|
||||
|
||||
// CToF converts a Celsius temperature to Fahrenheit.
|
||||
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }
|
||||
|
||||
// FToC converts a Fahrenheit temperature to Celsius.
|
||||
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }
|
||||
|
||||
//!-
|
23
vendor/gopl.io/ch2/tempconv/tempconv.go
generated
vendored
23
vendor/gopl.io/ch2/tempconv/tempconv.go
generated
vendored
@ -1,23 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
//!+
|
||||
|
||||
// Package tempconv performs Celsius and Fahrenheit conversions.
|
||||
package tempconv
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Celsius float64
|
||||
type Fahrenheit float64
|
||||
|
||||
const (
|
||||
AbsoluteZeroC Celsius = -273.15
|
||||
FreezingC Celsius = 0
|
||||
BoilingC Celsius = 100
|
||||
)
|
||||
|
||||
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
|
||||
func (f Fahrenheit) String() string { return fmt.Sprintf("%g°F", f) }
|
||||
|
||||
//!-
|
27
vendor/gopl.io/ch2/tempconv0/celsius.go
generated
vendored
27
vendor/gopl.io/ch2/tempconv0/celsius.go
generated
vendored
@ -1,27 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 39.
|
||||
//!+
|
||||
|
||||
// Package tempconv performs Celsius and Fahrenheit temperature computations.
|
||||
package tempconv
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Celsius float64
|
||||
type Fahrenheit float64
|
||||
|
||||
const (
|
||||
AbsoluteZeroC Celsius = -273.15
|
||||
FreezingC Celsius = 0
|
||||
BoilingC Celsius = 100
|
||||
)
|
||||
|
||||
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }
|
||||
|
||||
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }
|
||||
|
||||
//!-
|
||||
|
||||
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
|
45
vendor/gopl.io/ch2/tempconv0/tempconv_test.go
generated
vendored
45
vendor/gopl.io/ch2/tempconv0/tempconv_test.go
generated
vendored
@ -1,45 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package tempconv
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Example_one() {
|
||||
{
|
||||
//!+arith
|
||||
fmt.Printf("%g\n", BoilingC-FreezingC) // "100" °C
|
||||
boilingF := CToF(BoilingC)
|
||||
fmt.Printf("%g\n", boilingF-CToF(FreezingC)) // "180" °F
|
||||
//!-arith
|
||||
}
|
||||
/*
|
||||
//!+arith
|
||||
fmt.Printf("%g\n", boilingF-FreezingC) // compile error: type mismatch
|
||||
//!-arith
|
||||
*/
|
||||
|
||||
// Output:
|
||||
// 100
|
||||
// 180
|
||||
}
|
||||
|
||||
func Example_two() {
|
||||
//!+printf
|
||||
c := FToC(212.0)
|
||||
fmt.Println(c.String()) // "100°C"
|
||||
fmt.Printf("%v\n", c) // "100°C"; no need to call String explicitly
|
||||
fmt.Printf("%s\n", c) // "100°C"
|
||||
fmt.Println(c) // "100°C"
|
||||
fmt.Printf("%g\n", c) // "100"; does not call String
|
||||
fmt.Println(float64(c)) // "100"; does not call String
|
||||
//!-printf
|
||||
|
||||
// Output:
|
||||
// 100°C
|
||||
// 100°C
|
||||
// 100°C
|
||||
// 100°C
|
||||
// 100
|
||||
// 100
|
||||
}
|
44
vendor/gopl.io/ch3/basename1/main.go
generated
vendored
44
vendor/gopl.io/ch3/basename1/main.go
generated
vendored
@ -1,44 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 72.
|
||||
|
||||
// Basename1 reads file names from stdin and prints the base name of each one.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
input := bufio.NewScanner(os.Stdin)
|
||||
for input.Scan() {
|
||||
fmt.Println(basename(input.Text()))
|
||||
}
|
||||
// NOTE: ignoring potential errors from input.Err()
|
||||
}
|
||||
|
||||
//!+
|
||||
// basename removes directory components and a .suffix.
|
||||
// e.g., a => a, a.go => a, a/b/c.go => c, a/b.c.go => b.c
|
||||
func basename(s string) string {
|
||||
// Discard last '/' and everything before.
|
||||
for i := len(s) - 1; i >= 0; i-- {
|
||||
if s[i] == '/' {
|
||||
s = s[i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
// Preserve everything before last '.'.
|
||||
for i := len(s) - 1; i >= 0; i-- {
|
||||
if s[i] == '.' {
|
||||
s = s[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
//!-
|
36
vendor/gopl.io/ch3/basename2/main.go
generated
vendored
36
vendor/gopl.io/ch3/basename2/main.go
generated
vendored
@ -1,36 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 72.
|
||||
|
||||
// Basename2 reads file names from stdin and prints the base name of each one.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
input := bufio.NewScanner(os.Stdin)
|
||||
for input.Scan() {
|
||||
fmt.Println(basename(input.Text()))
|
||||
}
|
||||
// NOTE: ignoring potential errors from input.Err()
|
||||
}
|
||||
|
||||
// basename removes directory components and a trailing .suffix.
|
||||
// e.g., a => a, a.go => a, a/b/c.go => c, a/b.c.go => b.c
|
||||
//!+
|
||||
func basename(s string) string {
|
||||
slash := strings.LastIndex(s, "/") // -1 if "/" not found
|
||||
s = s[slash+1:]
|
||||
if dot := strings.LastIndex(s, "."); dot >= 0 {
|
||||
s = s[:dot]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
//!-
|
40
vendor/gopl.io/ch3/comma/main.go
generated
vendored
40
vendor/gopl.io/ch3/comma/main.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 73.
|
||||
|
||||
// Comma prints its argument numbers with a comma at each power of 1000.
|
||||
//
|
||||
// Example:
|
||||
// $ go build gopl.io/ch3/comma
|
||||
// $ ./comma 1 12 123 1234 1234567890
|
||||
// 1
|
||||
// 12
|
||||
// 123
|
||||
// 1,234
|
||||
// 1,234,567,890
|
||||
//
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for i := 1; i < len(os.Args); i++ {
|
||||
fmt.Printf(" %s\n", comma(os.Args[i]))
|
||||
}
|
||||
}
|
||||
|
||||
//!+
|
||||
// comma inserts commas in a non-negative decimal integer string.
|
||||
func comma(s string) string {
|
||||
n := len(s)
|
||||
if n <= 3 {
|
||||
return s
|
||||
}
|
||||
return comma(s[:n-3]) + "," + s[n-3:]
|
||||
}
|
||||
|
||||
//!-
|
84
vendor/gopl.io/ch3/mandelbrot/main.go
generated
vendored
84
vendor/gopl.io/ch3/mandelbrot/main.go
generated
vendored
@ -1,84 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 61.
|
||||
//!+
|
||||
|
||||
// Mandelbrot emits a PNG image of the Mandelbrot fractal.
|
||||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"math/cmplx"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const (
|
||||
xmin, ymin, xmax, ymax = -2, -2, +2, +2
|
||||
width, height = 1024, 1024
|
||||
)
|
||||
|
||||
img := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
for py := 0; py < height; py++ {
|
||||
y := float64(py)/height*(ymax-ymin) + ymin
|
||||
for px := 0; px < width; px++ {
|
||||
x := float64(px)/width*(xmax-xmin) + xmin
|
||||
z := complex(x, y)
|
||||
// Image point (px, py) represents complex value z.
|
||||
img.Set(px, py, mandelbrot(z))
|
||||
}
|
||||
}
|
||||
png.Encode(os.Stdout, img) // NOTE: ignoring errors
|
||||
}
|
||||
|
||||
func mandelbrot(z complex128) color.Color {
|
||||
const iterations = 200
|
||||
const contrast = 15
|
||||
|
||||
var v complex128
|
||||
for n := uint8(0); n < iterations; n++ {
|
||||
v = v*v + z
|
||||
if cmplx.Abs(v) > 2 {
|
||||
return color.Gray{255 - contrast*n}
|
||||
}
|
||||
}
|
||||
return color.Black
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
// Some other interesting functions:
|
||||
|
||||
func acos(z complex128) color.Color {
|
||||
v := cmplx.Acos(z)
|
||||
blue := uint8(real(v)*128) + 127
|
||||
red := uint8(imag(v)*128) + 127
|
||||
return color.YCbCr{192, blue, red}
|
||||
}
|
||||
|
||||
func sqrt(z complex128) color.Color {
|
||||
v := cmplx.Sqrt(z)
|
||||
blue := uint8(real(v)*128) + 127
|
||||
red := uint8(imag(v)*128) + 127
|
||||
return color.YCbCr{128, blue, red}
|
||||
}
|
||||
|
||||
// f(x) = x^4 - 1
|
||||
//
|
||||
// z' = z - f(z)/f'(z)
|
||||
// = z - (z^4 - 1) / (4 * z^3)
|
||||
// = z - (z - 1/z^3) / 4
|
||||
func newton(z complex128) color.Color {
|
||||
const iterations = 37
|
||||
const contrast = 7
|
||||
for i := uint8(0); i < iterations; i++ {
|
||||
z -= (z - 1/(z*z*z)) / 4
|
||||
if cmplx.Abs(z*z*z*z-1) < 1e-6 {
|
||||
return color.Gray{255 - contrast*i}
|
||||
}
|
||||
}
|
||||
return color.Black
|
||||
}
|
30
vendor/gopl.io/ch3/netflag/netflag.go
generated
vendored
30
vendor/gopl.io/ch3/netflag/netflag.go
generated
vendored
@ -1,30 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 77.
|
||||
|
||||
// Netflag demonstrates an integer type used as a bit field.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
. "net"
|
||||
)
|
||||
|
||||
//!+
|
||||
func IsUp(v Flags) bool { return v&FlagUp == FlagUp }
|
||||
func TurnDown(v *Flags) { *v &^= FlagUp }
|
||||
func SetBroadcast(v *Flags) { *v |= FlagBroadcast }
|
||||
func IsCast(v Flags) bool { return v&(FlagBroadcast|FlagMulticast) != 0 }
|
||||
|
||||
func main() {
|
||||
var v Flags = FlagMulticast | FlagUp
|
||||
fmt.Printf("%b %t\n", v, IsUp(v)) // "10001 true"
|
||||
TurnDown(&v)
|
||||
fmt.Printf("%b %t\n", v, IsUp(v)) // "10000 false"
|
||||
SetBroadcast(&v)
|
||||
fmt.Printf("%b %t\n", v, IsUp(v)) // "10010 false"
|
||||
fmt.Printf("%b %t\n", v, IsCast(v)) // "10010 true"
|
||||
}
|
||||
|
||||
//!-
|
33
vendor/gopl.io/ch3/printints/main.go
generated
vendored
33
vendor/gopl.io/ch3/printints/main.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 74.
|
||||
|
||||
// Printints demonstrates the use of bytes.Buffer to format a string.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//!+
|
||||
// intsToString is like fmt.Sprint(values) but adds commas.
|
||||
func intsToString(values []int) string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteByte('[')
|
||||
for i, v := range values {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
fmt.Fprintf(&buf, "%d", v)
|
||||
}
|
||||
buf.WriteByte(']')
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(intsToString([]int{1, 2, 3})) // "[1, 2, 3]"
|
||||
}
|
||||
|
||||
//!-
|
62
vendor/gopl.io/ch3/surface/main.go
generated
vendored
62
vendor/gopl.io/ch3/surface/main.go
generated
vendored
@ -1,62 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 58.
|
||||
//!+
|
||||
|
||||
// Surface computes an SVG rendering of a 3-D surface function.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
const (
|
||||
width, height = 600, 320 // canvas size in pixels
|
||||
cells = 100 // number of grid cells
|
||||
xyrange = 30.0 // axis ranges (-xyrange..+xyrange)
|
||||
xyscale = width / 2 / xyrange // pixels per x or y unit
|
||||
zscale = height * 0.4 // pixels per z unit
|
||||
angle = math.Pi / 6 // angle of x, y axes (=30°)
|
||||
)
|
||||
|
||||
var sin30, cos30 = math.Sin(angle), math.Cos(angle) // sin(30°), cos(30°)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("<svg xmlns='http://www.w3.org/2000/svg' "+
|
||||
"style='stroke: grey; fill: white; stroke-width: 0.7' "+
|
||||
"width='%d' height='%d'>", width, height)
|
||||
for i := 0; i < cells; i++ {
|
||||
for j := 0; j < cells; j++ {
|
||||
ax, ay := corner(i+1, j)
|
||||
bx, by := corner(i, j)
|
||||
cx, cy := corner(i, j+1)
|
||||
dx, dy := corner(i+1, j+1)
|
||||
fmt.Printf("<polygon points='%g,%g %g,%g %g,%g %g,%g'/>\n",
|
||||
ax, ay, bx, by, cx, cy, dx, dy)
|
||||
}
|
||||
}
|
||||
fmt.Println("</svg>")
|
||||
}
|
||||
|
||||
func corner(i, j int) (float64, float64) {
|
||||
// Find point (x,y) at corner of cell (i,j).
|
||||
x := xyrange * (float64(i)/cells - 0.5)
|
||||
y := xyrange * (float64(j)/cells - 0.5)
|
||||
|
||||
// Compute surface height z.
|
||||
z := f(x, y)
|
||||
|
||||
// Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).
|
||||
sx := width/2 + (x-y)*cos30*xyscale
|
||||
sy := height/2 + (x+y)*sin30*xyscale - z*zscale
|
||||
return sx, sy
|
||||
}
|
||||
|
||||
func f(x, y float64) float64 {
|
||||
r := math.Hypot(x, y) // distance from (0,0)
|
||||
return math.Sin(r) / r
|
||||
}
|
||||
|
||||
//!-
|
79
vendor/gopl.io/ch4/append/main.go
generated
vendored
79
vendor/gopl.io/ch4/append/main.go
generated
vendored
@ -1,79 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 88.
|
||||
|
||||
// Append illustrates the behavior of the built-in append function.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func appendslice(x []int, y ...int) []int {
|
||||
var z []int
|
||||
zlen := len(x) + len(y)
|
||||
if zlen <= cap(x) {
|
||||
// There is room to expand the slice.
|
||||
z = x[:zlen]
|
||||
} else {
|
||||
// There is insufficient space.
|
||||
// Grow by doubling, for amortized linear complexity.
|
||||
zcap := zlen
|
||||
if zcap < 2*len(x) {
|
||||
zcap = 2 * len(x)
|
||||
}
|
||||
z = make([]int, zlen, zcap)
|
||||
copy(z, x)
|
||||
}
|
||||
copy(z[len(x):], y)
|
||||
return z
|
||||
}
|
||||
|
||||
//!+append
|
||||
func appendInt(x []int, y int) []int {
|
||||
var z []int
|
||||
zlen := len(x) + 1
|
||||
if zlen <= cap(x) {
|
||||
// There is room to grow. Extend the slice.
|
||||
z = x[:zlen]
|
||||
} else {
|
||||
// There is insufficient space. Allocate a new array.
|
||||
// Grow by doubling, for amortized linear complexity.
|
||||
zcap := zlen
|
||||
if zcap < 2*len(x) {
|
||||
zcap = 2 * len(x)
|
||||
}
|
||||
z = make([]int, zlen, zcap)
|
||||
copy(z, x) // a built-in function; see text
|
||||
}
|
||||
z[len(x)] = y
|
||||
return z
|
||||
}
|
||||
|
||||
//!-append
|
||||
|
||||
//!+growth
|
||||
func main() {
|
||||
var x, y []int
|
||||
for i := 0; i < 10; i++ {
|
||||
y = appendInt(x, i)
|
||||
fmt.Printf("%d cap=%d\t%v\n", i, cap(y), y)
|
||||
x = y
|
||||
}
|
||||
}
|
||||
|
||||
//!-growth
|
||||
|
||||
/*
|
||||
//!+output
|
||||
0 cap=1 [0]
|
||||
1 cap=2 [0 1]
|
||||
2 cap=4 [0 1 2]
|
||||
3 cap=4 [0 1 2 3]
|
||||
4 cap=8 [0 1 2 3 4]
|
||||
5 cap=8 [0 1 2 3 4 5]
|
||||
6 cap=8 [0 1 2 3 4 5 6]
|
||||
7 cap=8 [0 1 2 3 4 5 6 7]
|
||||
8 cap=16 [0 1 2 3 4 5 6 7 8]
|
||||
9 cap=16 [0 1 2 3 4 5 6 7 8 9]
|
||||
//!-output
|
||||
*/
|
30
vendor/gopl.io/ch4/autoescape/main.go
generated
vendored
30
vendor/gopl.io/ch4/autoescape/main.go
generated
vendored
@ -1,30 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 117.
|
||||
|
||||
// Autoescape demonstrates automatic HTML escaping in html/template.
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
//!+
|
||||
func main() {
|
||||
const templ = `<p>A: {{.A}}</p><p>B: {{.B}}</p>`
|
||||
t := template.Must(template.New("escape").Parse(templ))
|
||||
var data struct {
|
||||
A string // untrusted plain text
|
||||
B template.HTML // trusted HTML
|
||||
}
|
||||
data.A = "<b>Hello!</b>"
|
||||
data.B = "<b>Hello!</b>"
|
||||
if err := t.Execute(os.Stdout, data); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
56
vendor/gopl.io/ch4/charcount/main.go
generated
vendored
56
vendor/gopl.io/ch4/charcount/main.go
generated
vendored
@ -1,56 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 97.
|
||||
//!+
|
||||
|
||||
// Charcount computes counts of Unicode characters.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func main() {
|
||||
counts := make(map[rune]int) // counts of Unicode characters
|
||||
var utflen [utf8.UTFMax + 1]int // count of lengths of UTF-8 encodings
|
||||
invalid := 0 // count of invalid UTF-8 characters
|
||||
|
||||
in := bufio.NewReader(os.Stdin)
|
||||
for {
|
||||
r, n, err := in.ReadRune() // returns rune, nbytes, error
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "charcount: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if r == unicode.ReplacementChar && n == 1 {
|
||||
invalid++
|
||||
continue
|
||||
}
|
||||
counts[r]++
|
||||
utflen[n]++
|
||||
}
|
||||
fmt.Printf("rune\tcount\n")
|
||||
for c, n := range counts {
|
||||
fmt.Printf("%q\t%d\n", c, n)
|
||||
}
|
||||
fmt.Print("\nlen\tcount\n")
|
||||
for i, n := range utflen {
|
||||
if i > 0 {
|
||||
fmt.Printf("%d\t%d\n", i, n)
|
||||
}
|
||||
}
|
||||
if invalid > 0 {
|
||||
fmt.Printf("\n%d invalid UTF-8 characters\n", invalid)
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
33
vendor/gopl.io/ch4/dedup/main.go
generated
vendored
33
vendor/gopl.io/ch4/dedup/main.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 96.
|
||||
|
||||
// Dedup prints only one instance of each line; duplicates are removed.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
//!+
|
||||
func main() {
|
||||
seen := make(map[string]bool) // a set of strings
|
||||
input := bufio.NewScanner(os.Stdin)
|
||||
for input.Scan() {
|
||||
line := input.Text()
|
||||
if !seen[line] {
|
||||
seen[line] = true
|
||||
fmt.Println(line)
|
||||
}
|
||||
}
|
||||
|
||||
if err := input.Err(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "dedup: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
46
vendor/gopl.io/ch4/embed/main.go
generated
vendored
46
vendor/gopl.io/ch4/embed/main.go
generated
vendored
@ -1,46 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 106.
|
||||
|
||||
// Embed demonstrates basic struct embedding.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Point struct{ X, Y int }
|
||||
|
||||
type Circle struct {
|
||||
Point
|
||||
Radius int
|
||||
}
|
||||
|
||||
type Wheel struct {
|
||||
Circle
|
||||
Spokes int
|
||||
}
|
||||
|
||||
func main() {
|
||||
var w Wheel
|
||||
//!+
|
||||
w = Wheel{Circle{Point{8, 8}, 5}, 20}
|
||||
|
||||
w = Wheel{
|
||||
Circle: Circle{
|
||||
Point: Point{X: 8, Y: 8},
|
||||
Radius: 5,
|
||||
},
|
||||
Spokes: 20, // NOTE: trailing comma necessary here (and at Radius)
|
||||
}
|
||||
|
||||
fmt.Printf("%#v\n", w)
|
||||
// Output:
|
||||
// Wheel{Circle:Circle{Point:Point{X:8, Y:8}, Radius:5}, Spokes:20}
|
||||
|
||||
w.X = 42
|
||||
|
||||
fmt.Printf("%#v\n", w)
|
||||
// Output:
|
||||
// Wheel{Circle:Circle{Point:Point{X:42, Y:8}, Radius:5}, Spokes:20}
|
||||
//!-
|
||||
}
|
35
vendor/gopl.io/ch4/github/github.go
generated
vendored
35
vendor/gopl.io/ch4/github/github.go
generated
vendored
@ -1,35 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 110.
|
||||
//!+
|
||||
|
||||
// Package github provides a Go API for the GitHub issue tracker.
|
||||
// See https://developer.github.com/v3/search/#search-issues.
|
||||
package github
|
||||
|
||||
import "time"
|
||||
|
||||
const IssuesURL = "https://api.github.com/search/issues"
|
||||
|
||||
type IssuesSearchResult struct {
|
||||
TotalCount int `json:"total_count"`
|
||||
Items []*Issue
|
||||
}
|
||||
|
||||
type Issue struct {
|
||||
Number int
|
||||
HTMLURL string `json:"html_url"`
|
||||
Title string
|
||||
State string
|
||||
User *User
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Body string // in Markdown format
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Login string
|
||||
HTMLURL string `json:"html_url"`
|
||||
}
|
||||
|
||||
//!-
|
53
vendor/gopl.io/ch4/github/search.go
generated
vendored
53
vendor/gopl.io/ch4/github/search.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
//!+
|
||||
|
||||
package github
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SearchIssues queries the GitHub issue tracker.
|
||||
func SearchIssues(terms []string) (*IssuesSearchResult, error) {
|
||||
q := url.QueryEscape(strings.Join(terms, " "))
|
||||
resp, err := http.Get(IssuesURL + "?q=" + q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//!-
|
||||
// For long-term stability, instead of http.Get, use the
|
||||
// variant below which adds an HTTP request header indicating
|
||||
// that only version 3 of the GitHub API is acceptable.
|
||||
//
|
||||
// req, err := http.NewRequest("GET", IssuesURL+"?q="+q, nil)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// req.Header.Set(
|
||||
// "Accept", "application/vnd.github.v3.text-match+json")
|
||||
// resp, err := http.DefaultClient.Do(req)
|
||||
//!+
|
||||
|
||||
// We must close resp.Body on all execution paths.
|
||||
// (Chapter 5 presents 'defer', which makes this simpler.)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
resp.Body.Close()
|
||||
return nil, fmt.Errorf("search query failed: %s", resp.Status)
|
||||
}
|
||||
|
||||
var result IssuesSearchResult
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
resp.Body.Close()
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
//!-
|
43
vendor/gopl.io/ch4/graph/main.go
generated
vendored
43
vendor/gopl.io/ch4/graph/main.go
generated
vendored
@ -1,43 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 99.
|
||||
|
||||
// Graph shows how to use a map of maps to represent a directed graph.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
//!+
|
||||
var graph = make(map[string]map[string]bool)
|
||||
|
||||
func addEdge(from, to string) {
|
||||
edges := graph[from]
|
||||
if edges == nil {
|
||||
edges = make(map[string]bool)
|
||||
graph[from] = edges
|
||||
}
|
||||
edges[to] = true
|
||||
}
|
||||
|
||||
func hasEdge(from, to string) bool {
|
||||
return graph[from][to]
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
func main() {
|
||||
addEdge("a", "b")
|
||||
addEdge("c", "d")
|
||||
addEdge("a", "d")
|
||||
addEdge("d", "a")
|
||||
fmt.Println(hasEdge("a", "b"))
|
||||
fmt.Println(hasEdge("c", "d"))
|
||||
fmt.Println(hasEdge("a", "d"))
|
||||
fmt.Println(hasEdge("d", "a"))
|
||||
fmt.Println(hasEdge("x", "b"))
|
||||
fmt.Println(hasEdge("c", "d"))
|
||||
fmt.Println(hasEdge("x", "d"))
|
||||
fmt.Println(hasEdge("d", "x"))
|
||||
|
||||
}
|
52
vendor/gopl.io/ch4/issues/main.go
generated
vendored
52
vendor/gopl.io/ch4/issues/main.go
generated
vendored
@ -1,52 +0,0 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 112.
|
||||
//!+
|
||||
|
||||
// Issues prints a table of GitHub issues matching the search terms.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"gopl.io/ch4/github"
|
||||
)
|
||||
|
||||
//!+
|
||||
func main() {
|
||||
result, err := github.SearchIssues(os.Args[1:])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%d issues:\n", result.TotalCount)
|
||||
for _, item := range result.Items {
|
||||
fmt.Printf("#%-5d %9.9s %.55s\n",
|
||||
item.Number, item.User.Login, item.Title)
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
/*
|
||||
//!+textoutput
|
||||
$ go build gopl.io/ch4/issues
|
||||
$ ./issues repo:golang/go is:open json decoder
|
||||
13 issues:
|
||||
#5680 eaigner encoding/json: set key converter on en/decoder
|
||||
#6050 gopherbot encoding/json: provide tokenizer
|
||||
#8658 gopherbot encoding/json: use bufio
|
||||
#8462 kortschak encoding/json: UnmarshalText confuses json.Unmarshal
|
||||
#5901 rsc encoding/json: allow override type marshaling
|
||||
#9812 klauspost encoding/json: string tag not symmetric
|
||||
#7872 extempora encoding/json: Encoder internally buffers full output
|
||||
#9650 cespare encoding/json: Decoding gives errPhase when unmarshalin
|
||||
#6716 gopherbot encoding/json: include field name in unmarshal error me
|
||||
#6901 lukescott encoding/json, encoding/xml: option to treat unknown fi
|
||||
#6384 joeshaw encoding/json: encode precise floating point integers u
|
||||
#6647 btracey x/tools/cmd/godoc: display type kind of each named type
|
||||
#4237 gjemiller encoding/base64: URLEncoding padding is optional
|
||||
//!-textoutput
|
||||
*/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user