Added a ringbuff datastructure

This commit is contained in:
Diptanu Choudhury 2016-05-09 06:35:53 -07:00
parent 13825f434e
commit 8abc594da1
2 changed files with 128 additions and 0 deletions

45
client/stats/ring.go Normal file
View 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
View 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
}