Initial commit
This commit is contained in:
72
README.md
Normal file
72
README.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# ring
|
||||||
|
--
|
||||||
|
import "git.sky/shenzhen/ring"
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
var DefaultCapacity int = 10
|
||||||
|
```
|
||||||
|
The DefaultCapacity of an uninitialized Ring buffer.
|
||||||
|
|
||||||
|
Changing this value only affects ring buffers created after it is changed.
|
||||||
|
|
||||||
|
#### type Ring
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Ring struct {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Type Ring implements a Circular Buffer. The default value of the Ring struct is
|
||||||
|
a valid (empty) Ring buffer with capacity DefaultCapacify.
|
||||||
|
|
||||||
|
#### func (Ring) Capacity
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r Ring) Capacity() int
|
||||||
|
```
|
||||||
|
Capacity returns the current capacity of the ring buffer.
|
||||||
|
|
||||||
|
#### func (*Ring) Dequeue
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *Ring) Dequeue() interface{}
|
||||||
|
```
|
||||||
|
Dequeue a value from the Ring buffer.
|
||||||
|
|
||||||
|
Returns nil if the ring buffer is empty.
|
||||||
|
|
||||||
|
#### func (*Ring) Enqueue
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *Ring) Enqueue(i interface{})
|
||||||
|
```
|
||||||
|
Enqueue a value into the Ring buffer.
|
||||||
|
|
||||||
|
#### func (*Ring) Peek
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *Ring) Peek() interface{}
|
||||||
|
```
|
||||||
|
Read the value that Dequeue would have dequeued without actually dequeuing it.
|
||||||
|
|
||||||
|
Returns nil if the ring buffer is empty.
|
||||||
|
|
||||||
|
#### func (*Ring) SetCapacity
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *Ring) SetCapacity(size int)
|
||||||
|
```
|
||||||
|
Set the maximum size of the ring buffer.
|
||||||
|
|
||||||
|
#### func (*Ring) Values
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *Ring) Values() []interface{}
|
||||||
|
```
|
||||||
|
Values returns a slice of all the values in the circular buffer without
|
||||||
|
modifying them at all. The returned slice can be modified independently of the
|
||||||
|
circular buffer. However, the values inside the slice are shared between the
|
||||||
|
slice and circular buffer.
|
||||||
141
ring.go
Normal file
141
ring.go
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
package ring
|
||||||
|
|
||||||
|
/*
|
||||||
|
The DefaultCapacity of an uninitialized Ring buffer.
|
||||||
|
|
||||||
|
Changing this value only affects ring buffers created after it is changed.
|
||||||
|
*/
|
||||||
|
var DefaultCapacity int = 10
|
||||||
|
|
||||||
|
/*
|
||||||
|
Type Ring implements a Circular Buffer.
|
||||||
|
The default value of the Ring struct is a valid (empty) Ring buffer with capacity DefaultCapacify.
|
||||||
|
*/
|
||||||
|
type Ring struct {
|
||||||
|
head int // the most recent value written
|
||||||
|
tail int // the least recent value written
|
||||||
|
buff []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set the maximum size of the ring buffer.
|
||||||
|
*/
|
||||||
|
func (r *Ring) SetCapacity(size int) {
|
||||||
|
r.checkInit()
|
||||||
|
r.extend(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Capacity returns the current capacity of the ring buffer.
|
||||||
|
*/
|
||||||
|
func (r Ring) Capacity() int {
|
||||||
|
return len(r.buff)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Enqueue a value into the Ring buffer.
|
||||||
|
*/
|
||||||
|
func (r *Ring) Enqueue(i interface{}) {
|
||||||
|
r.checkInit()
|
||||||
|
r.set(r.head+1, i)
|
||||||
|
old := r.head
|
||||||
|
r.head = r.mod(r.head+1)
|
||||||
|
if old != -1 && r.head == r.tail {
|
||||||
|
r.tail = r.mod(r.tail + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dequeue a value from the Ring buffer.
|
||||||
|
|
||||||
|
Returns nil if the ring buffer is empty.
|
||||||
|
*/
|
||||||
|
func (r *Ring) Dequeue() interface{} {
|
||||||
|
r.checkInit()
|
||||||
|
if r.head == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := r.get(r.tail)
|
||||||
|
if r.tail == r.head {
|
||||||
|
r.head = -1
|
||||||
|
r.tail = 0
|
||||||
|
} else {
|
||||||
|
r.tail = r.mod(r.tail + 1)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read the value that Dequeue would have dequeued without actually dequeuing it.
|
||||||
|
|
||||||
|
Returns nil if the ring buffer is empty.
|
||||||
|
*/
|
||||||
|
func (r *Ring) Peek() interface{} {
|
||||||
|
r.checkInit()
|
||||||
|
if r.head == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return r.get(r.tail)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Values returns a slice of all the values in the circular buffer without modifying them at all.
|
||||||
|
The returned slice can be modified independently of the circular buffer. However, the values inside the slice
|
||||||
|
are shared between the slice and circular buffer.
|
||||||
|
*/
|
||||||
|
func (r *Ring) Values() []interface{} {
|
||||||
|
if r.head == -1 {
|
||||||
|
return []interface{}{}
|
||||||
|
}
|
||||||
|
arr := make([]interface{}, 0, r.Capacity())
|
||||||
|
for i := 0; i < r.Capacity(); i++ {
|
||||||
|
idx := r.mod(i+r.tail)
|
||||||
|
arr = append(arr, r.get(idx))
|
||||||
|
if idx == r.head {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*** Unexported methods beyond this point.
|
||||||
|
**/
|
||||||
|
|
||||||
|
// sets a value at the given unmodified index and returns the modified index of the value
|
||||||
|
func (r *Ring) set(p int, v interface{}) {
|
||||||
|
r.buff[r.mod(p)] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets a value based at a given unmodified index
|
||||||
|
func (r *Ring) get(p int) interface{} {
|
||||||
|
return r.buff[r.mod(p)]
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the modified index of an unmodified index
|
||||||
|
func (r *Ring) mod(p int) int {
|
||||||
|
return p % len(r.buff)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Ring) checkInit() {
|
||||||
|
if r.buff == nil {
|
||||||
|
r.buff = make([]interface{}, DefaultCapacity)
|
||||||
|
for i := range r.buff {
|
||||||
|
r.buff[i] = nil
|
||||||
|
}
|
||||||
|
r.head, r.tail = -1, 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Ring) extend(size int) {
|
||||||
|
if size == len(r.buff) {
|
||||||
|
return
|
||||||
|
} else if size < len(r.buff) {
|
||||||
|
r.buff = r.buff[0:size]
|
||||||
|
}
|
||||||
|
newb := make([]interface{}, size-len(r.buff))
|
||||||
|
for i := range newb {
|
||||||
|
newb[i] = nil
|
||||||
|
}
|
||||||
|
r.buff = append(r.buff, newb...)
|
||||||
|
}
|
||||||
116
ring_test.go
Normal file
116
ring_test.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package ring
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSetsSize(t *testing.T) {
|
||||||
|
r := &Ring{}
|
||||||
|
r.SetCapacity(10)
|
||||||
|
if r.Capacity() != 10 {
|
||||||
|
t.Fatal("Size of ring was not 10", r.Capacity())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSavesSomeData(t *testing.T) {
|
||||||
|
r := Ring{}
|
||||||
|
r.SetCapacity(10)
|
||||||
|
for i := 0; i < 7; i++ {
|
||||||
|
r.Enqueue(i)
|
||||||
|
}
|
||||||
|
for i := 0; i < 7; i++ {
|
||||||
|
x := r.Dequeue()
|
||||||
|
if x != i {
|
||||||
|
t.Fatal("Unexpected response", x, "wanted", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReusesBuffer(t *testing.T) {
|
||||||
|
r := Ring{}
|
||||||
|
r.SetCapacity(10)
|
||||||
|
for i := 0; i < 7; i++ {
|
||||||
|
r.Enqueue(i)
|
||||||
|
}
|
||||||
|
for i := 0; i < 7; i++ {
|
||||||
|
r.Dequeue()
|
||||||
|
}
|
||||||
|
for i := 7; i < 14; i++ {
|
||||||
|
r.Enqueue(i)
|
||||||
|
}
|
||||||
|
for i := 7; i < 14; i++ {
|
||||||
|
x := r.Dequeue()
|
||||||
|
if x != i {
|
||||||
|
t.Fatal("Unexpected response", x, "wanted", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOverflowsBuffer(t *testing.T) {
|
||||||
|
r := Ring{}
|
||||||
|
r.SetCapacity(10)
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
r.Enqueue(i)
|
||||||
|
}
|
||||||
|
for i := 10; i < 20; i++ {
|
||||||
|
x := r.Dequeue()
|
||||||
|
if x != i {
|
||||||
|
t.Fatal("Unexpected response", x, "wanted", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPartiallyOverflows(t *testing.T) {
|
||||||
|
r := Ring{}
|
||||||
|
r.SetCapacity(10)
|
||||||
|
for i := 0; i < 15; i++ {
|
||||||
|
r.Enqueue(i)
|
||||||
|
}
|
||||||
|
for i := 5; i < 15; i++ {
|
||||||
|
x := r.Dequeue()
|
||||||
|
if x != i {
|
||||||
|
t.Fatal("Unexpected response", x, "wanted", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPeeks(t *testing.T) {
|
||||||
|
r := Ring{}
|
||||||
|
r.SetCapacity(10)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
r.Enqueue(i)
|
||||||
|
}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
r.Peek()
|
||||||
|
r.Peek()
|
||||||
|
x1 := r.Peek()
|
||||||
|
x := r.Dequeue()
|
||||||
|
if x != i {
|
||||||
|
t.Fatal("Unexpected response", x, "wanted", i)
|
||||||
|
}
|
||||||
|
if x1 != x {
|
||||||
|
t.Fatal("Unexpected response", x1, "wanted", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConstructsArr(t *testing.T) {
|
||||||
|
r := Ring{}
|
||||||
|
r.SetCapacity(10)
|
||||||
|
v := r.Values()
|
||||||
|
if len(v) != 0 {
|
||||||
|
t.Fatal("Unexpected values", v, "wanted len of", 0)
|
||||||
|
}
|
||||||
|
for i := 1; i < 21; i++ {
|
||||||
|
r.Enqueue(i)
|
||||||
|
l := i
|
||||||
|
if l > 10 {
|
||||||
|
l = 10
|
||||||
|
}
|
||||||
|
v = r.Values()
|
||||||
|
if len(v) != l {
|
||||||
|
t.Fatal("Unexpected values", v, "wanted len of", l, "index", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user