123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- package freecache
- import (
- "bytes"
- "errors"
- "fmt"
- "io"
- )
- var ErrOutOfRange = errors.New("out of range")
- // Ring buffer has a fixed size, when data exceeds the
- // size, old data will be overwritten by new data.
- // It only contains the data in the stream from begin to end
- type RingBuf struct {
- begin int64 // beginning offset of the data stream.
- end int64 // ending offset of the data stream.
- data []byte
- index int //range from '0' to 'len(rb.data)-1'
- }
- func NewRingBuf(size int, begin int64) (rb RingBuf) {
- rb.data = make([]byte, size)
- rb.begin = begin
- rb.end = begin
- rb.index = 0
- return
- }
- // Create a copy of the buffer.
- func (rb *RingBuf) Dump() []byte {
- dump := make([]byte, len(rb.data))
- copy(dump, rb.data)
- return dump
- }
- func (rb *RingBuf) String() string {
- return fmt.Sprintf("[size:%v, start:%v, end:%v, index:%v]", len(rb.data), rb.begin, rb.end, rb.index)
- }
- func (rb *RingBuf) Size() int64 {
- return int64(len(rb.data))
- }
- func (rb *RingBuf) Begin() int64 {
- return rb.begin
- }
- func (rb *RingBuf) End() int64 {
- return rb.end
- }
- // read up to len(p), at off of the data stream.
- func (rb *RingBuf) ReadAt(p []byte, off int64) (n int, err error) {
- if off > rb.end || off < rb.begin {
- err = ErrOutOfRange
- return
- }
- var readOff int
- if rb.end-rb.begin < int64(len(rb.data)) {
- readOff = int(off - rb.begin)
- } else {
- readOff = rb.index + int(off-rb.begin)
- }
- if readOff >= len(rb.data) {
- readOff -= len(rb.data)
- }
- readEnd := readOff + int(rb.end-off)
- if readEnd <= len(rb.data) {
- n = copy(p, rb.data[readOff:readEnd])
- } else {
- n = copy(p, rb.data[readOff:])
- if n < len(p) {
- n += copy(p[n:], rb.data[:readEnd-len(rb.data)])
- }
- }
- if n < len(p) {
- err = io.EOF
- }
- return
- }
- func (rb *RingBuf) Write(p []byte) (n int, err error) {
- if len(p) > len(rb.data) {
- err = ErrOutOfRange
- return
- }
- for n < len(p) {
- written := copy(rb.data[rb.index:], p[n:])
- rb.end += int64(written)
- n += written
- rb.index += written
- if rb.index >= len(rb.data) {
- rb.index -= len(rb.data)
- }
- }
- if int(rb.end-rb.begin) > len(rb.data) {
- rb.begin = rb.end - int64(len(rb.data))
- }
- return
- }
- func (rb *RingBuf) WriteAt(p []byte, off int64) (n int, err error) {
- if off+int64(len(p)) > rb.end || off < rb.begin {
- err = ErrOutOfRange
- return
- }
- var writeOff int
- if rb.end-rb.begin < int64(len(rb.data)) {
- writeOff = int(off - rb.begin)
- } else {
- writeOff = rb.index + int(off-rb.begin)
- }
- if writeOff > len(rb.data) {
- writeOff -= len(rb.data)
- }
- writeEnd := writeOff + int(rb.end-off)
- if writeEnd <= len(rb.data) {
- n = copy(rb.data[writeOff:writeEnd], p)
- } else {
- n = copy(rb.data[writeOff:], p)
- if n < len(p) {
- n += copy(rb.data[:writeEnd-len(rb.data)], p[n:])
- }
- }
- return
- }
- func (rb *RingBuf) EqualAt(p []byte, off int64) bool {
- if off+int64(len(p)) > rb.end || off < rb.begin {
- return false
- }
- var readOff int
- if rb.end-rb.begin < int64(len(rb.data)) {
- readOff = int(off - rb.begin)
- } else {
- readOff = rb.index + int(off-rb.begin)
- }
- if readOff >= len(rb.data) {
- readOff -= len(rb.data)
- }
- readEnd := readOff + len(p)
- if readEnd <= len(rb.data) {
- return bytes.Equal(p, rb.data[readOff:readEnd])
- } else {
- firstLen := len(rb.data) - readOff
- equal := bytes.Equal(p[:firstLen], rb.data[readOff:])
- if equal {
- secondLen := len(p) - firstLen
- equal = bytes.Equal(p[firstLen:], rb.data[:secondLen])
- }
- return equal
- }
- }
- // Evacuate read the data at off, then write it to the the data stream,
- // Keep it from being overwritten by new data.
- func (rb *RingBuf) Evacuate(off int64, length int) (newOff int64) {
- if off+int64(length) > rb.end || off < rb.begin {
- return -1
- }
- var readOff int
- if rb.end-rb.begin < int64(len(rb.data)) {
- readOff = int(off - rb.begin)
- } else {
- readOff = rb.index + int(off-rb.begin)
- }
- if readOff >= len(rb.data) {
- readOff -= len(rb.data)
- }
- if readOff == rb.index {
- // no copy evacuate
- rb.index += length
- if rb.index >= len(rb.data) {
- rb.index -= len(rb.data)
- }
- } else if readOff < rb.index {
- var n = copy(rb.data[rb.index:], rb.data[readOff:readOff+length])
- rb.index += n
- if rb.index == len(rb.data) {
- rb.index = copy(rb.data, rb.data[readOff+n:readOff+length])
- }
- } else {
- var readEnd = readOff + length
- var n int
- if readEnd <= len(rb.data) {
- n = copy(rb.data[rb.index:], rb.data[readOff:readEnd])
- rb.index += n
- if rb.index == len(rb.data) {
- rb.index = copy(rb.data, rb.data[readOff+n:readEnd])
- }
- } else {
- n = copy(rb.data[rb.index:], rb.data[readOff:])
- rb.index += n
- var tail = length - n
- n = copy(rb.data[rb.index:], rb.data[:tail])
- rb.index += n
- if rb.index == len(rb.data) {
- rb.index = copy(rb.data, rb.data[n:tail])
- }
- }
- }
- newOff = rb.end
- rb.end += int64(length)
- if rb.begin < rb.end-int64(len(rb.data)) {
- rb.begin = rb.end - int64(len(rb.data))
- }
- return
- }
- func (rb *RingBuf) Resize(newSize int) {
- if len(rb.data) == newSize {
- return
- }
- newData := make([]byte, newSize)
- var offset int
- if rb.end-rb.begin == int64(len(rb.data)) {
- offset = rb.index
- }
- if int(rb.end-rb.begin) > newSize {
- discard := int(rb.end-rb.begin) - newSize
- offset = (offset + discard) % len(rb.data)
- rb.begin = rb.end - int64(newSize)
- }
- n := copy(newData, rb.data[offset:])
- if n < newSize {
- copy(newData[n:], rb.data[:offset])
- }
- rb.data = newData
- rb.index = 0
- }
- func (rb *RingBuf) Skip(length int64) {
- rb.end += length
- rb.index += int(length)
- for rb.index >= len(rb.data) {
- rb.index -= len(rb.data)
- }
- if int(rb.end-rb.begin) > len(rb.data) {
- rb.begin = rb.end - int64(len(rb.data))
- }
- }
|