diff options
author | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:22:53 +0200 |
---|---|---|
committer | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:22:53 +0200 |
commit | 8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 (patch) | |
tree | 4449f2036cccf162e8417cc5841a35815b3e7ac5 /src/pkg/io | |
parent | c8bf49ef8a92e2337b69c14b9b88396efe498600 (diff) | |
download | golang-upstream/1.3.tar.gz |
Imported Upstream version 1.3upstream/1.3
Diffstat (limited to 'src/pkg/io')
-rw-r--r-- | src/pkg/io/io.go | 1 | ||||
-rw-r--r-- | src/pkg/io/io_test.go | 20 | ||||
-rw-r--r-- | src/pkg/io/ioutil/blackhole.go | 23 | ||||
-rw-r--r-- | src/pkg/io/ioutil/ioutil.go | 14 | ||||
-rw-r--r-- | src/pkg/io/multi.go | 11 | ||||
-rw-r--r-- | src/pkg/io/multi_test.go | 27 |
6 files changed, 67 insertions, 29 deletions
diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go index f7073ffc0..022fdb676 100644 --- a/src/pkg/io/io.go +++ b/src/pkg/io/io.go @@ -74,6 +74,7 @@ type Reader interface { // It returns the number of bytes written from p (0 <= n <= len(p)) // and any error encountered that caused the write to stop early. // Write must return a non-nil error if it returns n < len(p). +// Write must not modify the slice data, even temporarily. type Writer interface { Write(p []byte) (n int, err error) } diff --git a/src/pkg/io/io_test.go b/src/pkg/io/io_test.go index bd7a82f17..57db1fbf0 100644 --- a/src/pkg/io/io_test.go +++ b/src/pkg/io/io_test.go @@ -281,6 +281,8 @@ func TestSectionReader_ReadAt(t *testing.T) { {data: dat, off: 3, n: len(dat), bufLen: len(dat) / 2, at: 2, exp: dat[5 : 5+len(dat)/2], err: nil}, {data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 - 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: nil}, {data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 + 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: EOF}, + {data: dat, off: 0, n: 0, bufLen: 0, at: -1, exp: "", err: EOF}, + {data: dat, off: 0, n: 0, bufLen: 0, at: 1, exp: "", err: EOF}, } for i, tt := range tests { r := strings.NewReader(tt.data) @@ -319,3 +321,21 @@ func TestSectionReader_Seek(t *testing.T) { t.Errorf("Read = %v, %v; want 0, EOF", n, err) } } + +func TestSectionReader_Size(t *testing.T) { + tests := []struct { + data string + want int64 + }{ + {"a long sample data, 1234567890", 30}, + {"", 0}, + } + + for _, tt := range tests { + r := strings.NewReader(tt.data) + sr := NewSectionReader(r, 0, int64(len(tt.data))) + if got := sr.Size(); got != tt.want { + t.Errorf("Size = %v; want %v", got, tt.want) + } + } +} diff --git a/src/pkg/io/ioutil/blackhole.go b/src/pkg/io/ioutil/blackhole.go deleted file mode 100644 index 101d2c121..000000000 --- a/src/pkg/io/ioutil/blackhole.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ioutil - -var blackHoleBuf = make(chan []byte, 1) - -func blackHole() []byte { - select { - case b := <-blackHoleBuf: - return b - default: - } - return make([]byte, 8192) -} - -func blackHolePut(p []byte) { - select { - case blackHoleBuf <- p: - default: - } -} diff --git a/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go index b2508b789..909a81563 100644 --- a/src/pkg/io/ioutil/ioutil.go +++ b/src/pkg/io/ioutil/ioutil.go @@ -10,6 +10,7 @@ import ( "io" "os" "sort" + "sync" ) // readAll reads from r until an error or EOF and returns the data it read @@ -136,14 +137,21 @@ func (devNull) WriteString(s string) (int, error) { return len(s), nil } +var blackHolePool = sync.Pool{ + New: func() interface{} { + b := make([]byte, 8192) + return &b + }, +} + func (devNull) ReadFrom(r io.Reader) (n int64, err error) { - buf := blackHole() - defer blackHolePut(buf) + bufp := blackHolePool.Get().(*[]byte) readSize := 0 for { - readSize, err = r.Read(buf) + readSize, err = r.Read(*bufp) n += int64(readSize) if err != nil { + blackHolePool.Put(bufp) if err == io.EOF { return n, nil } diff --git a/src/pkg/io/multi.go b/src/pkg/io/multi.go index 2c7e816cf..e26cc53e9 100644 --- a/src/pkg/io/multi.go +++ b/src/pkg/io/multi.go @@ -26,9 +26,12 @@ func (mr *multiReader) Read(p []byte) (n int, err error) { // MultiReader returns a Reader that's the logical concatenation of // the provided input readers. They're read sequentially. Once all -// inputs are drained, Read will return EOF. +// inputs have returned EOF, Read will return EOF. If any of the readers +// return a non-nil, non-EOF error, Read will return that error. func MultiReader(readers ...Reader) Reader { - return &multiReader{readers} + r := make([]Reader, len(readers)) + copy(r, readers) + return &multiReader{r} } type multiWriter struct { @@ -52,5 +55,7 @@ func (t *multiWriter) Write(p []byte) (n int, err error) { // MultiWriter creates a writer that duplicates its writes to all the // provided writers, similar to the Unix tee(1) command. func MultiWriter(writers ...Writer) Writer { - return &multiWriter{writers} + w := make([]Writer, len(writers)) + copy(w, writers) + return &multiWriter{w} } diff --git a/src/pkg/io/multi_test.go b/src/pkg/io/multi_test.go index eb717f7bc..56c6769a9 100644 --- a/src/pkg/io/multi_test.go +++ b/src/pkg/io/multi_test.go @@ -9,6 +9,7 @@ import ( "crypto/sha1" "fmt" . "io" + "io/ioutil" "strings" "testing" ) @@ -86,3 +87,29 @@ func TestMultiWriter(t *testing.T) { t.Errorf("expected %q; got %q", sourceString, sink.String()) } } + +// Test that MultiReader copies the input slice and is insulated from future modification. +func TestMultiReaderCopy(t *testing.T) { + slice := []Reader{strings.NewReader("hello world")} + r := MultiReader(slice...) + slice[0] = nil + data, err := ioutil.ReadAll(r) + if err != nil || string(data) != "hello world" { + t.Errorf("ReadAll() = %q, %v, want %q, nil", data, err, "hello world") + } +} + +// Test that MultiWriter copies the input slice and is insulated from future modification. +func TestMultiWriterCopy(t *testing.T) { + var buf bytes.Buffer + slice := []Writer{&buf} + w := MultiWriter(slice...) + slice[0] = nil + n, err := w.Write([]byte("hello world")) + if err != nil || n != 11 { + t.Errorf("Write(`hello world`) = %d, %v, want 11, nil", n, err) + } + if buf.String() != "hello world" { + t.Errorf("buf.String() = %q, want %q", buf.String(), "hello world") + } +} |