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 }