package circbuf import ( "fmt" ) // Buffer implements a circular buffer. It is a fixed size, // and new writes overwrite older data, such that for a buffer // of size N, for any amount of writes, only the last N bytes // are retained. type Buffer struct { data []byte size int64 writeCursor int64 written int64 } // NewBuffer creates a new buffer of a given size. The size // must be greater than 0. func NewBuffer(size int64) (*Buffer, error) { if size <= 0 { return nil, fmt.Errorf("Size must be positive") } b := &Buffer{ size: size, data: make([]byte, size), } return b, nil } // Write writes up to len(buf) bytes to the internal ring, // overriding older data if necessary. func (b *Buffer) Write(buf []byte) (int, error) { // Account for total bytes written n := len(buf) b.written += int64(n) // If the buffer is larger than ours, then we only care // about the last size bytes anyways if int64(n) > b.size { buf = buf[int64(n)-b.size:] } // Copy in place remain := b.size - b.writeCursor copy(b.data[b.writeCursor:], buf) if int64(len(buf)) > remain { copy(b.data, buf[remain:]) } // Update location of the cursor b.writeCursor = ((b.writeCursor + int64(len(buf))) % b.size) return n, nil } // Size returns the size of the buffer func (b *Buffer) Size() int64 { return b.size } // TotalWritten provides the total number of bytes written func (b *Buffer) TotalWritten() int64 { return b.written } // Bytes provides a slice of the bytes written. This // slice should not be written to. func (b *Buffer) Bytes() []byte { switch { case b.written >= b.size && b.writeCursor == 0: return b.data case b.written > b.size: out := make([]byte, b.size) copy(out, b.data[b.writeCursor:]) copy(out[b.size-b.writeCursor:], b.data[:b.writeCursor]) return out default: return b.data[:b.writeCursor] } } // Reset resets the buffer so it has no content. func (b *Buffer) Reset() { b.writeCursor = 0 b.written = 0 } // String returns the contents of the buffer as a string func (b *Buffer) String() string { return string(b.Bytes()) }