Added a ringbuff datastructure
This commit is contained in:
parent
13825f434e
commit
8abc594da1
45
client/stats/ring.go
Normal file
45
client/stats/ring.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package stats
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultCap = 60
|
||||
)
|
||||
|
||||
type RingBuff struct {
|
||||
head int
|
||||
buff []interface{}
|
||||
}
|
||||
|
||||
func NewRingBuff(capacity int) (*RingBuff, error) {
|
||||
if capacity < 1 {
|
||||
return nil, fmt.Errorf("can not create a ring buffer with capacity: %v", capacity)
|
||||
}
|
||||
return &RingBuff{buff: make([]interface{}, capacity), head: -1}, nil
|
||||
}
|
||||
|
||||
func (r *RingBuff) Enqueue(value interface{}) {
|
||||
r.head += 1
|
||||
if r.head == len(r.buff) {
|
||||
r.head = 0
|
||||
}
|
||||
r.buff[r.head] = value
|
||||
}
|
||||
|
||||
func (r *RingBuff) Peek() interface{} {
|
||||
return r.buff[r.head]
|
||||
}
|
||||
|
||||
func (r *RingBuff) Values() []interface{} {
|
||||
if r.head == len(r.buff)-1 {
|
||||
vals := make([]interface{}, len(r.buff))
|
||||
copy(vals, r.buff)
|
||||
return vals
|
||||
}
|
||||
|
||||
slice1 := r.buff[r.head+1:]
|
||||
slice2 := r.buff[:r.head+1]
|
||||
return append(slice1, slice2...)
|
||||
}
|
83
client/stats/ring_test.go
Normal file
83
client/stats/ring_test.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package stats
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRingBuffInvalid(t *testing.T) {
|
||||
if _, err := NewRingBuff(0); err == nil {
|
||||
t.Fatalf("expected err")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRingBuffEnqueue(t *testing.T) {
|
||||
rb, err := NewRingBuff(3)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
rb.Enqueue(1)
|
||||
rb.Enqueue(2)
|
||||
rb.Enqueue(3)
|
||||
if val := rb.Peek(); val != 3 {
|
||||
t.Fatalf("expected: %v, actual: %v", 3, val)
|
||||
}
|
||||
|
||||
rb.Enqueue(4)
|
||||
rb.Enqueue(5)
|
||||
if val := rb.Peek(); val != 5 {
|
||||
t.Fatalf("expected: %v, actual: %v", 5, val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRingBuffValues(t *testing.T) {
|
||||
rb, err := NewRingBuff(3)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
rb.Enqueue(1)
|
||||
rb.Enqueue(2)
|
||||
rb.Enqueue(3)
|
||||
rb.Enqueue(4)
|
||||
|
||||
expected := []interface{}{2, 3, 4}
|
||||
if !sliceEq(expected, rb.Values()) {
|
||||
t.Fatalf("expected: %v, actual: %v", expected, rb.Values())
|
||||
}
|
||||
|
||||
rb.Enqueue(5)
|
||||
expected = []interface{}{3, 4, 5}
|
||||
if !sliceEq(expected, rb.Values()) {
|
||||
t.Fatalf("expected: %v, actual: %v", expected, rb.Values())
|
||||
}
|
||||
|
||||
rb.Enqueue(6)
|
||||
expected = []interface{}{4, 5, 6}
|
||||
if !sliceEq(expected, rb.Values()) {
|
||||
t.Fatalf("expected: %v, actual: %v", expected, rb.Values())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func sliceEq(slice1, slice2 []interface{}) bool {
|
||||
|
||||
if slice1 == nil && slice2 == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if slice1 == nil || slice2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(slice1) != len(slice2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range slice1 {
|
||||
if slice1[i] != slice2[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
Loading…
Reference in a new issue