ringbuffer.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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. func (rb *RingBuffer[T]) Add(t T) {
  23. rb.mu.Lock()
  24. defer rb.mu.Unlock()
  25. if len(rb.buf) < rb.max {
  26. rb.buf = append(rb.buf, t)
  27. } else {
  28. rb.buf[rb.pos] = t
  29. rb.pos = (rb.pos + 1) % rb.max
  30. }
  31. }
  32. // GetAll returns a copy of all the entries in the ring buffer in the order they
  33. // were added.
  34. func (rb *RingBuffer[T]) GetAll() []T {
  35. if rb == nil {
  36. return nil
  37. }
  38. rb.mu.Lock()
  39. defer rb.mu.Unlock()
  40. out := make([]T, len(rb.buf))
  41. for i := 0; i < len(rb.buf); i++ {
  42. x := (rb.pos + i) % rb.max
  43. out[i] = rb.buf[x]
  44. }
  45. return out
  46. }
  47. // Len returns the number of elements in the ring buffer. Note that this value
  48. // could change immediately after being returned if a concurrent caller
  49. // modifies the buffer.
  50. func (rb *RingBuffer[T]) Len() int {
  51. if rb == nil {
  52. return 0
  53. }
  54. rb.mu.Lock()
  55. defer rb.mu.Unlock()
  56. return len(rb.buf)
  57. }
  58. // Clear will empty the ring buffer.
  59. func (rb *RingBuffer[T]) Clear() {
  60. rb.mu.Lock()
  61. defer rb.mu.Unlock()
  62. rb.pos = 0
  63. rb.buf = nil
  64. }