diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-04-15 06:34:27 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-04-15 06:34:27 +0000 |
commit | 058672f818da2e2fd3eed44737939291cc02d809 (patch) | |
tree | cd6e318f2abeabc01493804644c205c72f5eb7f3 /libgo/go/io | |
parent | ac2c6188d9bb781b7055c102c0af536fd6ca3366 (diff) | |
download | gcc-058672f818da2e2fd3eed44737939291cc02d809.tar.gz |
2016-04-15 Basile Starynkevitch <basile@starynkevitch.net>
{{merging with even more of GCC 6, using subversion 1.9
svn merge -r229501:229700 ^/trunk
}}
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@235005 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/io')
-rw-r--r-- | libgo/go/io/io.go | 27 | ||||
-rw-r--r-- | libgo/go/io/io_test.go | 50 | ||||
-rw-r--r-- | libgo/go/io/ioutil/tempfile.go | 4 | ||||
-rw-r--r-- | libgo/go/io/pipe.go | 5 |
4 files changed, 80 insertions, 6 deletions
diff --git a/libgo/go/io/io.go b/libgo/go/io/io.go index 7507a84929f..8851eaf00ab 100644 --- a/libgo/go/io/io.go +++ b/libgo/go/io/io.go @@ -54,7 +54,7 @@ var ErrNoProgress = errors.New("multiple Read calls return no data or error") // An instance of this general case is that a Reader returning // a non-zero number of bytes at the end of the input stream may // return either err == EOF or err == nil. The next Read should -// return 0, EOF regardless. +// return 0, EOF. // // Callers should always process the n > 0 bytes returned before // considering the error err. Doing so correctly handles I/O errors @@ -273,8 +273,8 @@ type stringWriter interface { WriteString(s string) (n int, err error) } -// WriteString writes the contents of the string s to w, which accepts an array of bytes. -// If w already implements a WriteString method, it is invoked directly. +// WriteString writes the contents of the string s to w, which accepts a slice of bytes. +// If w implements a WriteString method, it is invoked directly. func WriteString(w Writer, s string) (n int, err error) { if sw, ok := w.(stringWriter); ok { return sw.WriteString(s) @@ -348,6 +348,23 @@ func CopyN(dst Writer, src Reader, n int64) (written int64, err error) { // Otherwise, if dst implements the ReaderFrom interface, // the copy is implemented by calling dst.ReadFrom(src). func Copy(dst Writer, src Reader) (written int64, err error) { + return copyBuffer(dst, src, nil) +} + +// CopyBuffer is identical to Copy except that it stages through the +// provided buffer (if one is required) rather than allocating a +// temporary one. If buf is nil, one is allocated; otherwise if it has +// zero length, CopyBuffer panics. +func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { + if buf != nil && len(buf) == 0 { + panic("empty buffer in io.CopyBuffer") + } + return copyBuffer(dst, src, buf) +} + +// copyBuffer is the actual implementation of Copy and CopyBuffer. +// if buf is nil, one is allocated. +func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { // If the reader has a WriteTo method, use it to do the copy. // Avoids an allocation and a copy. if wt, ok := src.(WriterTo); ok { @@ -357,7 +374,9 @@ func Copy(dst Writer, src Reader) (written int64, err error) { if rt, ok := dst.(ReaderFrom); ok { return rt.ReadFrom(src) } - buf := make([]byte, 32*1024) + if buf == nil { + buf = make([]byte, 32*1024) + } for { nr, er := src.Read(buf) if nr > 0 { diff --git a/libgo/go/io/io_test.go b/libgo/go/io/io_test.go index 57db1fbf0bf..e892574b0b5 100644 --- a/libgo/go/io/io_test.go +++ b/libgo/go/io/io_test.go @@ -20,7 +20,7 @@ type Buffer struct { WriterTo // conflicts with and hides bytes.Buffer's WriterTo. } -// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and CopyN. +// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy, CopyBuffer and CopyN. func TestCopy(t *testing.T) { rb := new(Buffer) @@ -32,6 +32,26 @@ func TestCopy(t *testing.T) { } } +func TestCopyBuffer(t *testing.T) { + rb := new(Buffer) + wb := new(Buffer) + rb.WriteString("hello, world.") + CopyBuffer(wb, rb, make([]byte, 1)) // Tiny buffer to keep it honest. + if wb.String() != "hello, world." { + t.Errorf("CopyBuffer did not work properly") + } +} + +func TestCopyBufferNil(t *testing.T) { + rb := new(Buffer) + wb := new(Buffer) + rb.WriteString("hello, world.") + CopyBuffer(wb, rb, nil) // Should allocate a buffer. + if wb.String() != "hello, world." { + t.Errorf("CopyBuffer did not work properly") + } +} + func TestCopyReadFrom(t *testing.T) { rb := new(Buffer) wb := new(bytes.Buffer) // implements ReadFrom. @@ -78,6 +98,34 @@ func TestCopyPriority(t *testing.T) { } } +type zeroErrReader struct { + err error +} + +func (r zeroErrReader) Read(p []byte) (int, error) { + return copy(p, []byte{0}), r.err +} + +type errWriter struct { + err error +} + +func (w errWriter) Write([]byte) (int, error) { + return 0, w.err +} + +// In case a Read results in an error with non-zero bytes read, and +// the subsequent Write also results in an error, the error from Write +// is returned, as it is the one that prevented progressing further. +func TestCopyReadErrWriteErr(t *testing.T) { + er, ew := errors.New("readError"), errors.New("writeError") + r, w := zeroErrReader{err: er}, errWriter{err: ew} + n, err := Copy(w, r) + if n != 0 || err != ew { + t.Errorf("Copy(zeroErrReader, errWriter) = %d, %v; want 0, writeError", n, err) + } +} + func TestCopyN(t *testing.T) { rb := new(Buffer) wb := new(Buffer) diff --git a/libgo/go/io/ioutil/tempfile.go b/libgo/go/io/ioutil/tempfile.go index 4a06e9756fb..61d4a7ad37d 100644 --- a/libgo/go/io/ioutil/tempfile.go +++ b/libgo/go/io/ioutil/tempfile.go @@ -55,7 +55,9 @@ func TempFile(dir, prefix string) (f *os.File, err error) { f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) if os.IsExist(err) { if nconflict++; nconflict > 10 { + randmu.Lock() rand = reseed() + randmu.Unlock() } continue } @@ -82,7 +84,9 @@ func TempDir(dir, prefix string) (name string, err error) { err = os.Mkdir(try, 0700) if os.IsExist(err) { if nconflict++; nconflict > 10 { + randmu.Lock() rand = reseed() + randmu.Unlock() } continue } diff --git a/libgo/go/io/pipe.go b/libgo/go/io/pipe.go index f65354a7f25..179515e78d3 100644 --- a/libgo/go/io/pipe.go +++ b/libgo/go/io/pipe.go @@ -168,7 +168,10 @@ func (w *PipeWriter) Close() error { } // CloseWithError closes the writer; subsequent reads from the -// read half of the pipe will return no bytes and the error err. +// read half of the pipe will return no bytes and the error err, +// or EOF if err is nil. +// +// CloseWithError always returns nil. func (w *PipeWriter) CloseWithError(err error) error { w.p.wclose(err) return nil |