Source File
	tail.go
Belonging Package
	go.pact.im/x/extraio
package extraioimport ()// TailReader buffers the last n bytes read from the underlying io.Reader. That// is, its Read method does not return last n bytes read. Use Tail method to get// the underlying buffer on EOF.//// Note that its Read method may return zero byte count with a nil error if read// bytes fit into the underlying buffer. Some io.Reader client implementations// return io.ErrNoProgress error when many calls to Read have failed to return// any data or error.type TailReader struct {reader io.Readercur int // mutablebuf []byte // mutable}// NewTailReader returns a new reader that buffers last n bytes read from r.func ( io.Reader, uint) *TailReader {var []byteif != 0 {= make([]byte, 0, )}return &TailReader{reader: ,buf: ,}}// Reset resets the reader’s state.func ( *TailReader) () {.buf = .buf[:0]}// Length returns the length of the underlying buffer. It is faster than calling// len(r.Tail()) since the underlying buffer may not be contiguous and Tail has// to linearize it to return a contiguous slice of bytes.func ( *TailReader) () int {return len(.buf)}// Tail returns the buffer with last read bytes. The underlying buffer may not// be contiguous and Tail linearizes the contents before returning a contiguous// byte slice.func ( *TailReader) () []byte {.linearize()return .buf}// Read implements the io.Reader interface. It reads from the underlying// io.Reader but keeps the last n read bytes in the internal ring buffer.func ( *TailReader) ( []byte) (int, error) {, := .reader.Read()if <= 0 || .buf == nil {return ,}:= cap(.buf):= len(.buf):= -switch {// Case 1. Data fits into the free buffer space.case <= :.buf = append(.buf, [:]...)= 0// Case 2. Data exceeds buffer capacity.case >= :if == 0 {rotate([:], -):= .buf[.cur:]:= .buf[:.cur]swap([len():], )swap(, )} else {swap(.buf, [-:]).buf = .buf[:]copy(.buf[:], [-:])-=rotate([:], -)}// Case 3. Not enough free space but data fits into the buffer.default:if == 0 {:= swap(.buf[.cur:], [:]).cur = (.cur + ) %= swap(.buf[.cur:], [:]).cur = (.cur + ) %} else {.buf = append(.buf, [:]...)copy(, [:])-=swap(.buf, [:]).cur =}}return ,}// linearize makes the underlying ring buffer contiguous.func ( *TailReader) () {rotate(.buf, .cur).cur = 0}// swap swaps elements between dst and src slices. It returns the number of// swapped elements, that is, min(len(dst), len(src)).func (, []byte) int {:= min(len(), len())for := 0; < ; ++ {[], [] = [], []}return}// rotate performs in-place left rotation of the slice by n positions from the// start for positive n. If n is negative, the slice is right rotated by the// absolute value of n.//// Examples://// rotate([]byte("lohel"), 2)// => []byte("hello")//// rotate([]byte("45123"), 2)// => []byte("12345")//// rotate([]byte("34512"), -2)// => []byte("12345")func ( []byte, int) {:= len()if == 0 || == 1 {return}%=if == 0 || == {return}if < 0 {+=}reverse([:])reverse([:])reverse()}// reverse performs in-place reversal of the slice.func ( []byte) {for , := 0, len()-1; < ; , = +1, -1 {[], [] = [], []}}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)