github.com/weedge/lib@v0.0.0-20230424045628-a36dcc1d90e4/container/ringbuf/ringbuf.go (about)

     1  package ringbuf
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  )
     9  
    10  var ErrOutOfRange = errors.New("out of range")
    11  
    12  // Ring buffer has a fixed size, when data exceeds the
    13  // size, old data will be overwritten by new data.
    14  // It only contains the data in the stream from begin to end
    15  type RingBuf struct {
    16  	begin int64 // beginning offset of the data stream.
    17  	end   int64 // ending offset of the data stream.
    18  	data  []byte
    19  	index int //range from '0' to 'len(rb.data)-1'
    20  }
    21  
    22  func NewRingBuf(size int, begin int64) (rb RingBuf) {
    23  	rb.data = make([]byte, size)
    24  	rb.begin = begin
    25  	rb.end = begin
    26  	rb.index = 0
    27  	return
    28  }
    29  
    30  // Create a copy of the buffer.
    31  func (rb *RingBuf) Dump() []byte {
    32  	dump := make([]byte, len(rb.data))
    33  	copy(dump, rb.data)
    34  	return dump
    35  }
    36  
    37  func (rb *RingBuf) String() string {
    38  	return fmt.Sprintf("[size:%v, start:%v, end:%v, index:%v]", len(rb.data), rb.begin, rb.end, rb.index)
    39  }
    40  
    41  func (rb *RingBuf) Size() int64 {
    42  	return int64(len(rb.data))
    43  }
    44  
    45  func (rb *RingBuf) Begin() int64 {
    46  	return rb.begin
    47  }
    48  
    49  func (rb *RingBuf) End() int64 {
    50  	return rb.end
    51  }
    52  
    53  // read up to len(p), at off of the data stream.
    54  func (rb *RingBuf) ReadAt(p []byte, off int64) (n int, err error) {
    55  	if off > rb.end || off < rb.begin {
    56  		err = ErrOutOfRange
    57  		return
    58  	}
    59  	var readOff int
    60  	if rb.end-rb.begin < int64(len(rb.data)) {
    61  		readOff = int(off - rb.begin)
    62  	} else {
    63  		readOff = rb.index + int(off-rb.begin)
    64  	}
    65  	if readOff >= len(rb.data) {
    66  		readOff -= len(rb.data)
    67  	}
    68  	readEnd := readOff + int(rb.end-off)
    69  	if readEnd <= len(rb.data) {
    70  		n = copy(p, rb.data[readOff:readEnd])
    71  	} else {
    72  		n = copy(p, rb.data[readOff:])
    73  		if n < len(p) {
    74  			n += copy(p[n:], rb.data[:readEnd-len(rb.data)])
    75  		}
    76  	}
    77  	if n < len(p) {
    78  		err = io.EOF
    79  	}
    80  	return
    81  }
    82  
    83  func (rb *RingBuf) Write(p []byte) (n int, err error) {
    84  	if len(p) > len(rb.data) {
    85  		err = ErrOutOfRange
    86  		return
    87  	}
    88  	for n < len(p) {
    89  		written := copy(rb.data[rb.index:], p[n:])
    90  		rb.end += int64(written)
    91  		n += written
    92  		rb.index += written
    93  		if rb.index >= len(rb.data) {
    94  			rb.index -= len(rb.data)
    95  		}
    96  	}
    97  	if int(rb.end-rb.begin) > len(rb.data) {
    98  		rb.begin = rb.end - int64(len(rb.data))
    99  	}
   100  	return
   101  }
   102  
   103  func (rb *RingBuf) WriteAt(p []byte, off int64) (n int, err error) {
   104  	if off+int64(len(p)) > rb.end || off < rb.begin {
   105  		err = ErrOutOfRange
   106  		return
   107  	}
   108  	var writeOff int
   109  	if rb.end-rb.begin < int64(len(rb.data)) {
   110  		writeOff = int(off - rb.begin)
   111  	} else {
   112  		writeOff = rb.index + int(off-rb.begin)
   113  	}
   114  	if writeOff > len(rb.data) {
   115  		writeOff -= len(rb.data)
   116  	}
   117  	writeEnd := writeOff + int(rb.end-off)
   118  	if writeEnd <= len(rb.data) {
   119  		n = copy(rb.data[writeOff:writeEnd], p)
   120  	} else {
   121  		n = copy(rb.data[writeOff:], p)
   122  		if n < len(p) {
   123  			n += copy(rb.data[:writeEnd-len(rb.data)], p[n:])
   124  		}
   125  	}
   126  	return
   127  }
   128  
   129  func (rb *RingBuf) EqualAt(p []byte, off int64) bool {
   130  	if off+int64(len(p)) > rb.end || off < rb.begin {
   131  		return false
   132  	}
   133  	var readOff int
   134  	if rb.end-rb.begin < int64(len(rb.data)) {
   135  		readOff = int(off - rb.begin)
   136  	} else {
   137  		readOff = rb.index + int(off-rb.begin)
   138  	}
   139  	if readOff >= len(rb.data) {
   140  		readOff -= len(rb.data)
   141  	}
   142  	readEnd := readOff + len(p)
   143  	if readEnd <= len(rb.data) {
   144  		return bytes.Equal(p, rb.data[readOff:readEnd])
   145  	} else {
   146  		firstLen := len(rb.data) - readOff
   147  		equal := bytes.Equal(p[:firstLen], rb.data[readOff:])
   148  		if equal {
   149  			secondLen := len(p) - firstLen
   150  			equal = bytes.Equal(p[firstLen:], rb.data[:secondLen])
   151  		}
   152  		return equal
   153  	}
   154  }
   155  
   156  // Evacuate read the data at off, then write it to the the data stream,
   157  // Keep it from being overwritten by new data.
   158  func (rb *RingBuf) Evacuate(off int64, length int) (newOff int64) {
   159  	if off+int64(length) > rb.end || off < rb.begin {
   160  		return -1
   161  	}
   162  	var readOff int
   163  	if rb.end-rb.begin < int64(len(rb.data)) {
   164  		readOff = int(off - rb.begin)
   165  	} else {
   166  		readOff = rb.index + int(off-rb.begin)
   167  	}
   168  	if readOff >= len(rb.data) {
   169  		readOff -= len(rb.data)
   170  	}
   171  
   172  	if readOff == rb.index {
   173  		// no copy evacuate
   174  		rb.index += length
   175  		if rb.index >= len(rb.data) {
   176  			rb.index -= len(rb.data)
   177  		}
   178  	} else if readOff < rb.index {
   179  		var n = copy(rb.data[rb.index:], rb.data[readOff:readOff+length])
   180  		rb.index += n
   181  		if rb.index == len(rb.data) {
   182  			rb.index = copy(rb.data, rb.data[readOff+n:readOff+length])
   183  		}
   184  	} else {
   185  		var readEnd = readOff + length
   186  		var n int
   187  		if readEnd <= len(rb.data) {
   188  			n = copy(rb.data[rb.index:], rb.data[readOff:readEnd])
   189  			rb.index += n
   190  		} else {
   191  			n = copy(rb.data[rb.index:], rb.data[readOff:])
   192  			rb.index += n
   193  			var tail = length - n
   194  			n = copy(rb.data[rb.index:], rb.data[:tail])
   195  			rb.index += n
   196  			if rb.index == len(rb.data) {
   197  				rb.index = copy(rb.data, rb.data[n:tail])
   198  			}
   199  		}
   200  	}
   201  	newOff = rb.end
   202  	rb.end += int64(length)
   203  	if rb.begin < rb.end-int64(len(rb.data)) {
   204  		rb.begin = rb.end - int64(len(rb.data))
   205  	}
   206  	return
   207  }
   208  
   209  func (rb *RingBuf) Resize(newSize int) {
   210  	if len(rb.data) == newSize {
   211  		return
   212  	}
   213  	newData := make([]byte, newSize)
   214  	var offset int
   215  	if rb.end-rb.begin == int64(len(rb.data)) {
   216  		offset = rb.index
   217  	}
   218  	if int(rb.end-rb.begin) > newSize {
   219  		discard := int(rb.end-rb.begin) - newSize
   220  		offset = (offset + discard) % len(rb.data)
   221  		rb.begin = rb.end - int64(newSize)
   222  	}
   223  	n := copy(newData, rb.data[offset:])
   224  	if n < newSize {
   225  		copy(newData[n:], rb.data[:offset])
   226  	}
   227  	rb.data = newData
   228  	rb.index = 0
   229  }
   230  
   231  func (rb *RingBuf) Skip(length int64) {
   232  	rb.end += length
   233  	rb.index += int(length)
   234  	for rb.index >= len(rb.data) {
   235  		rb.index -= len(rb.data)
   236  	}
   237  	if int(rb.end-rb.begin) > len(rb.data) {
   238  		rb.begin = rb.end - int64(len(rb.data))
   239  	}
   240  }