uquic/utils/ringbuffer.go
2016-05-21 17:19:01 +07:00

95 lines
2.2 KiB
Go

package utils
import (
"errors"
"io"
)
// RingBuffer is a ring buffer
type RingBuffer interface {
Write(p []byte, offset uint64) error
Read(n uint64) ([]byte, uint64, error)
Clear(n uint64) error
Len() uint64
}
type ringBuffer struct {
data []byte
length uint64
readPosition uint64
writePosition uint64
writeCapacity uint64 // remaining number of bytes that can be written
}
// NewRingBuffer creates a new ring buffer
func NewRingBuffer(length uint64) RingBuffer {
return &ringBuffer{
data: make([]byte, length, length),
length: length,
writeCapacity: length,
}
}
// Writes copies the bytes of p into the buffer, if there's enough space
// it doesn't do any partial writes. If there's not enough space, it returns an io.EOF
func (b *ringBuffer) Write(p []byte, offset uint64) error {
len := uint64(len(p))
if len+offset > b.writeCapacity {
return io.EOF
}
writePosition := b.writePosition + offset
if writePosition+len < b.length {
copy(b.data[writePosition:], p)
} else {
copy(b.data[writePosition:b.length], p[:b.length-writePosition])
copy(b.data, p[b.length-writePosition:])
}
b.writePosition = (writePosition + len) % b.length
b.writeCapacity -= len
return nil
}
// Read tries to read n bytes
// when reaching the end of the internal byte slice, it returns all bytes until the end, but no eror. It should then be called again to get the rest of the data
func (b *ringBuffer) Read(n uint64) ([]byte, uint64, error) {
var data []byte
var err error
var bytesRead uint64
diff := b.writePosition - b.readPosition
if n <= diff {
bytesRead = n
}
if n >= diff {
bytesRead = diff
err = io.EOF
}
if b.readPosition+bytesRead > b.length {
bytesRead = b.length - b.readPosition
}
data = b.data[b.readPosition : b.readPosition+bytesRead]
b.readPosition += bytesRead
return data, bytesRead, err
}
// Clear marks n bytes as being actually processed and allows us to overwrite them
func (b *ringBuffer) Clear(n uint64) error {
if b.writeCapacity+n > b.length {
return errors.New("Can't clear that much space")
}
b.writeCapacity += n
return nil
}
// Len gets the length of the underlying byte-slice
func (b *ringBuffer) Len() uint64 {
return b.length
}