diff --git a/benchmark_test.go b/benchmark_test.go index f0cdcc6..493b786 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -28,9 +28,18 @@ func BenchmarkEnqueue(b *testing.B) { func BenchmarkDequeue(b *testing.B) { rb := New[int](2 * 1024 * 1024) - rb.n = b.N + rb.n = len(rb.a) b.ResetTimer() for i := 0; i < b.N; i++ { _, _ = rb.Dequeue() } } + +func BenchmarkPeek(b *testing.B) { + rb := New[int](2 * 1024 * 1024) + rb.n = len(rb.a) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = rb.Peek(i) + } +} diff --git a/ringbuf.go b/ringbuf.go index de80a76..67a60d7 100644 --- a/ringbuf.go +++ b/ringbuf.go @@ -2,9 +2,9 @@ package ringbuf // Buffer provides ring buffer. type Buffer[T any] struct { - d []T - r int - n int + a []T + rx int + n int } // New creates a ring buffer with specified capacity. @@ -13,18 +13,22 @@ func New[T any](capacity int) *Buffer[T] { panic("capacity must be large than 0") } return &Buffer[T]{ - d: make([]T, capacity), + a: make([]T, capacity), } } // Enqueue puts a value to last of the buffer. func (b *Buffer[T]) Enqueue(v T) { - b.d[(b.r+b.n)%len(b.d)] = v - if b.n < len(b.d) { + wx := b.rx + b.n + if wx >= len(b.a) { + wx -= len(b.a) + } + b.a[wx] = v + if b.n < len(b.a) { b.n++ - } else { - b.incR() + return } + b.rxInc() } // Dequeue retrieves a value. @@ -33,9 +37,9 @@ func (b *Buffer[T]) Dequeue() (T, bool) { if b.n <= 0 { return zero, false } - v := b.d[b.r] - b.d[b.r] = zero - b.incR() + v := b.a[b.rx] + b.a[b.rx] = zero + b.rxInc() b.n-- return v, true } @@ -43,11 +47,11 @@ func (b *Buffer[T]) Dequeue() (T, bool) { // Clear remove all values. func (b *Buffer[T]) Clear() { var zero T - for b.n > 0 { - b.d[b.r] = zero - b.incR() - b.n-- + for i := range b.a { + b.a[i] = zero } + b.rx = 0 + b.n = 0 } // Empty checks the buffer is empty or not. @@ -55,24 +59,34 @@ func (b *Buffer[T]) Empty() bool { return b.n == 0 } -func (b *Buffer[T]) incR() int { - b.r++ - if b.r == len(b.d) { - b.r = 0 +// rxInc increments rx. +func (b *Buffer[T]) rxInc() int { + b.rx++ + if b.rx == len(b.a) { + b.rx = 0 } - return b.r + return b.rx +} + +// Cap returns capacity of the ringbuf. +func (b *Buffer[T]) Cap() int { + return len(b.a) } -// Len returns number of valid items in the ringbuf +// Len returns number of valid items in the ringbuf. func (b *Buffer[T]) Len() int { return b.n } -// Peek peeks a n'th value in ringbuf without removing. +// Peek peeks a n'th value in the ringbuf without removing. func (b *Buffer[T]) Peek(n int) T { var zero T if n < 0 || n >= b.n { return zero } - return b.d[(b.r+n)%len(b.d)] + rx := b.rx + n + if rx >= len(b.a) { + rx -= len(b.a) + } + return b.a[rx] } diff --git a/ringbuf_test.go b/ringbuf_test.go index 66b3199..22f2cd3 100644 --- a/ringbuf_test.go +++ b/ringbuf_test.go @@ -5,6 +5,9 @@ import "testing" func TestRing(t *testing.T) { check := func(n int, in []int, exp []int) { b := New[int](n) + if cap := b.Cap(); cap != n { + t.Errorf("unexpectecd capacity: want=%d got=%d", n, cap) + } for _, v := range in { b.Enqueue(v) } @@ -23,6 +26,9 @@ func TestRing(t *testing.T) { if ok { t.Errorf("more value: w=%v n=%d in=%v", w, n, in) } + if cap := b.Cap(); cap != n { + t.Errorf("unexpectecd capacity: want=%d got=%d", n, cap) + } } for _, d := range []struct {