blob: 5865507de149d5cd6f14058e8efe0355d38a2091 [file] [log] [blame]
// Copyright 2015 The Vanadium 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 vom
import (
"io"
)
const minBufFree = 1024 // buffers always have at least 1K free after growth
// encbuf manages the write buffer for encoders. The approach is similar to
// bytes.Buffer, but the implementation is simplified to only deal with many
// writes followed by a read of the whole buffer.
type encbuf struct {
buf []byte
end int // [0, end) is data that's already written
}
func newEncbuf() *encbuf {
return &encbuf{
buf: make([]byte, minBufFree),
}
}
// Bytes returns a slice of the bytes written so far.
func (b *encbuf) Bytes() []byte { return b.buf[:b.end] }
// Len returns the number of bytes written so far.
func (b *encbuf) Len() int { return b.end }
// Reset the length to 0 to start a new round of writes.
func (b *encbuf) Reset() { b.end = 0 }
// reserve at least min free bytes in the buffer.
func (b *encbuf) tryReserve(min int) {
if len(b.buf)-b.end < min {
newlen := len(b.buf) * 2
if newlen-b.end < min {
newlen = b.end + min + minBufFree
}
newbuf := make([]byte, newlen)
copy(newbuf, b.buf[:b.end])
b.buf = newbuf
}
}
// Grow the buffer by n bytes, and returns those bytes.
//
// Different from bytes.Buffer.Grow, which doesn't return the bytes. Although
// this makes expandingEncbuf slightly easier to misuse, it helps to improve performance
// by avoiding unnecessary copying.
func (b *encbuf) Grow(n int) []byte {
b.tryReserve(n)
oldend := b.end
b.end += n
return b.buf[oldend:b.end]
}
// WriteOneByte writes byte c into the buffer.
func (b *encbuf) WriteOneByte(c byte) {
b.tryReserve(1)
b.buf[b.end] = c
b.end++
}
// Write writes a byte slice to the buffer.
func (b *encbuf) Write(p []byte) {
b.tryReserve(len(p))
b.end += copy(b.buf[b.end:], p)
}
// decbuf manages the read buffer for decoders. The approach is similar to
// bufio.Reader, but the API is better suited for fast decoding.
type decbuf struct {
buf []byte
beg, end int // [beg, end) is data read from reader but unread by the user
lim int // number of bytes left in limit, or -1 for no limit
reader io.Reader
// It's faster to hold end than to use the len and cap properties of buf,
// since end is cheaper to update than buf.
version Version
}
// newDecbuf returns a new decbuf that fills its internal buffer by reading r.
func newDecbuf(r io.Reader) *decbuf {
return &decbuf{
buf: make([]byte, minBufFree),
lim: -1,
reader: r,
}
}
// newDecbufFromBytes returns a new decbuf that reads directly from b.
func newDecbufFromBytes(b []byte) *decbuf {
return &decbuf{
buf: b,
end: len(b),
lim: -1,
reader: alwaysEOFReader{},
}
}
type alwaysEOFReader struct{}
func (alwaysEOFReader) Read([]byte) (int, error) { return 0, io.EOF }
// Reset resets the buffer so it has no data.
func (b *decbuf) Reset() {
b.beg = 0
b.end = 0
b.lim = -1
}
// SetLimit sets a limit to the bytes that are returned by decbuf; after a limit
// is set, subsequent reads cannot read past the limit, even if more bytes are
// available. Attempts to read past the limit return io.EOF. Call RemoveLimit
// to remove the limit.
//
// REQUIRES: limit >=0,
func (b *decbuf) SetLimit(limit int) {
b.lim = limit
}
func (b *decbuf) HasDataAvailable() bool {
return b.lim != 0 // -1 or positive
}
func (b *decbuf) Limit() int {
return b.lim
}
// RemoveLimit removes the limit, and returns the number of leftover bytes.
// Returns -1 if no limit was set.
func (b *decbuf) RemoveLimit() int {
leftover := b.lim
b.lim = -1
return leftover
}
// fill the buffer with at least min bytes of data. Returns an error if fewer
// than min bytes could be filled. Doesn't advance the read position.
func (b *decbuf) fill(min int) error {
switch avail := b.end - b.beg; {
case avail >= min:
// Fastpath - enough bytes are available.
return nil
case len(b.buf) < min:
// The buffer isn't big enough. Make a new buffer that's big enough and
// copy existing data to the front.
newlen := len(b.buf) * 2
if newlen < min+minBufFree {
newlen = min + minBufFree
}
newbuf := make([]byte, newlen)
b.end = copy(newbuf, b.buf[b.beg:b.end])
b.beg = 0
b.buf = newbuf
default:
// The buffer is big enough. Move existing data to the front.
b.moveDataToFront()
}
// INVARIANT: len(b.buf)-b.beg >= min
//
// Fill [b.end:] until min bytes are available. We must loop since Read may
// return success with fewer bytes than requested.
for b.end-b.beg < min {
switch nread, err := b.reader.Read(b.buf[b.end:]); {
case nread > 0:
b.end += nread
case err != nil:
return err
}
}
return nil
}
// moveDataToFront moves existing data in buf to the front, so that b.beg is 0.
func (b *decbuf) moveDataToFront() {
b.end = copy(b.buf, b.buf[b.beg:b.end])
b.beg = 0
}
// ReadSmall returns a buffer with the next n bytes, and increments the read
// position past those bytes. Returns an error if fewer than n bytes are
// available.
//
// The returned slice points directly at our internal buffer, and is only valid
// until the next decbuf call.
//
// REQUIRES: n >= 0
func (b *decbuf) ReadSmall(n int) ([]byte, error) {
if b.lim > -1 {
if b.lim < n {
b.lim = 0
return nil, io.EOF
}
b.lim -= n
}
if err := b.fill(n); err != nil {
return nil, err
}
buf := b.buf[b.beg : b.beg+n]
b.beg += n
return buf, nil
}
// PeekSmall returns a buffer with at least the next n bytes, but possibly
// more. The read position isn't incremented. Returns an error if fewer than
// min bytes are available.
//
// The returned slice points directly at our internal buffer, and is only valid
// until the next decbuf call.
//
// REQUIRES: min >= 0
func (b *decbuf) PeekSmall(min int) ([]byte, error) {
if b.lim > -1 && b.lim < min {
return nil, io.EOF
}
if err := b.fill(min); err != nil {
return nil, err
}
return b.buf[b.beg:b.end], nil
}
// Skip increments the read position past the next n bytes. Returns an error if
// fewer than n bytes are available.
//
// REQUIRES: n >= 0
func (b *decbuf) Skip(n int) error {
if b.lim > -1 {
if b.lim < n {
n = b.lim
return io.EOF
}
b.lim -= n
}
// If enough bytes are available, just update indices.
avail := b.end - b.beg
if avail >= n {
b.beg += n
return nil
}
n -= avail
// Keep reading into buf until we've read enough bytes.
for {
switch nread, err := b.reader.Read(b.buf); {
case nread > 0:
if nread >= n {
b.beg = n
b.end = nread
return nil
}
n -= nread
case err != nil:
return err
}
}
}
// ReadByte returns the next byte, and increments the read position.
func (b *decbuf) ReadByte() (byte, error) {
if b.lim > -1 {
if b.lim == 0 {
return 0, io.EOF
}
b.lim--
}
if err := b.fill(1); err != nil {
return 0, err
}
ret := b.buf[b.beg]
b.beg++
return ret, nil
}
// PeekByte returns the next byte, without changing the read position.
func (b *decbuf) PeekByte() (byte, error) {
if b.lim == 0 {
return 0, io.EOF
}
if err := b.fill(1); err != nil {
return 0, err
}
return b.buf[b.beg], nil
}
// ReadIntoBuf reads the next len(p) bytes into p, and increments the read position
// past those bytes. Returns an error if fewer than len(p) bytes are available.
func (b *decbuf) ReadIntoBuf(p []byte) error {
if b.lim > -1 {
if b.lim < len(p) {
return io.EOF
}
b.lim -= len(p)
}
// Copy bytes from the buffer.
ncopy := copy(p, b.buf[b.beg:b.end])
b.beg += ncopy
p = p[ncopy:]
// Keep reading into p until we've read enough bytes.
for len(p) > 0 {
switch nread, err := b.reader.Read(p); {
case nread > 0:
p = p[nread:]
case err != nil:
return err
}
}
return nil
}