1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
package utils
import (
"fmt"
)
var _ = fmt.Print
func rb_min(a, b uint64) uint64 {
if a < b {
return a
} else {
return b
}
}
type RingBuffer[T any] struct {
buffer []T
read_pos uint64
use_count uint64
}
func NewRingBuffer[T any](size uint64) *RingBuffer[T] {
return &RingBuffer[T]{
buffer: make([]T, size),
}
}
func (self *RingBuffer[T]) Len() uint64 {
return self.use_count
}
func (self *RingBuffer[T]) Capacity() uint64 {
return uint64(len(self.buffer))
}
func (self *RingBuffer[T]) Clear() {
self.read_pos = 0
self.use_count = 0
}
func (self *RingBuffer[T]) Grow(new_size uint64) {
if new_size <= self.Capacity() {
return
}
buf := make([]T, new_size)
if self.use_count > 0 {
self.ReadTillEmpty(buf)
}
self.buffer = buf
self.read_pos = 0
}
func (self *RingBuffer[T]) WriteTillFull(p ...T) uint64 {
ssz := self.Capacity()
available := ssz - self.use_count
sz := rb_min(uint64(len(p)), available)
if sz == 0 {
return 0
}
tail := (self.read_pos + self.use_count) % ssz
write_end := (self.read_pos + self.use_count + sz) % ssz
self.use_count += sz
p = p[:sz]
if tail <= write_end {
copy(self.buffer[tail:], p)
} else {
first_write := ssz - tail
copy(self.buffer[tail:], p[:first_write])
copy(self.buffer, p[first_write:])
}
return sz
}
func (self *RingBuffer[T]) WriteAllAndDiscardOld(p ...T) {
ssz := self.Capacity()
left := uint64(len(p))
if left >= ssz { // Fast path
extra := left - ssz
copy(self.buffer, p[extra:])
self.read_pos = 0
self.use_count = ssz
return
}
for {
written := self.WriteTillFull(p...)
p = p[written:]
left = uint64(len(p))
if left == 0 {
break
}
self.slices_to_read(left)
}
}
func (self *RingBuffer[T]) ReadTillEmpty(p []T) uint64 {
a, b := self.slices_to_read(uint64(len(p)))
copy(p, a)
copy(p[len(a):], b)
return uint64(len(a)) + uint64(len(b))
}
func (self *RingBuffer[T]) ReadAll() []T {
ans := make([]T, self.Len())
self.ReadTillEmpty(ans)
return ans
}
func (self *RingBuffer[T]) slices_to_read(sz uint64) ([]T, []T) {
ssz := self.Capacity()
sz = rb_min(sz, self.use_count)
head := self.read_pos
end_read := (head + sz) % ssz
self.use_count -= sz
self.read_pos = end_read
if end_read > head || sz == 0 {
return self.buffer[head:end_read], self.buffer[0:0]
}
first_read := ssz - head
return self.buffer[head : head+first_read], self.buffer[0 : sz-first_read]
}
|