ring.go 2.4 KB

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