ringbuffer.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package ringbuffer contains a fixed-size concurrency-safe generic ring
  4. // buffer.
  5. package ringbuffer
  6. import "sync"
  7. // New creates a new RingBuffer containing at most max items.
  8. func New[T any](max int) *RingBuffer[T] {
  9. return &RingBuffer[T]{
  10. max: max,
  11. }
  12. }
  13. // RingBuffer is a concurrency-safe ring buffer.
  14. type RingBuffer[T any] struct {
  15. mu sync.Mutex
  16. pos int
  17. buf []T
  18. max int
  19. }
  20. // Add appends a new item to the RingBuffer, possibly overwriting the oldest
  21. // item in the buffer if it is already full.
  22. //
  23. // It does nothing if rb is nil.
  24. func (rb *RingBuffer[T]) Add(t T) {
  25. if rb == nil {
  26. return
  27. }
  28. rb.mu.Lock()
  29. defer rb.mu.Unlock()
  30. if len(rb.buf) < rb.max {
  31. rb.buf = append(rb.buf, t)
  32. } else {
  33. rb.buf[rb.pos] = t
  34. rb.pos = (rb.pos + 1) % rb.max
  35. }
  36. }
  37. // GetAll returns a copy of all the entries in the ring buffer in the order they
  38. // were added.
  39. //
  40. // It returns nil if rb is nil.
  41. func (rb *RingBuffer[T]) GetAll() []T {
  42. if rb == nil {
  43. return nil
  44. }
  45. rb.mu.Lock()
  46. defer rb.mu.Unlock()
  47. out := make([]T, len(rb.buf))
  48. for i := range len(rb.buf) {
  49. x := (rb.pos + i) % rb.max
  50. out[i] = rb.buf[x]
  51. }
  52. return out
  53. }
  54. // Len returns the number of elements in the ring buffer. Note that this value
  55. // could change immediately after being returned if a concurrent caller
  56. // modifies the buffer.
  57. func (rb *RingBuffer[T]) Len() int {
  58. if rb == nil {
  59. return 0
  60. }
  61. rb.mu.Lock()
  62. defer rb.mu.Unlock()
  63. return len(rb.buf)
  64. }
  65. // Clear will empty the ring buffer.
  66. func (rb *RingBuffer[T]) Clear() {
  67. rb.mu.Lock()
  68. defer rb.mu.Unlock()
  69. rb.pos = 0
  70. rb.buf = nil
  71. }