mirror of
https://github.com/xtaci/kcp-go.git
synced 2026-10-19 16:14:38 +00:00
add ring
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
package kcp
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Ring struct {
|
||||
head int
|
||||
tail int
|
||||
elements []interface{}
|
||||
}
|
||||
|
||||
func NewRing(size int) *Ring {
|
||||
if size <= 8 {
|
||||
size = 8 // Ensure a minimum size
|
||||
}
|
||||
return &Ring{
|
||||
head: 0,
|
||||
tail: 0,
|
||||
elements: make([]interface{}, size),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Ring) Len() int {
|
||||
if r.head <= r.tail {
|
||||
return r.tail - r.head
|
||||
}
|
||||
return len(r.elements) - r.head + r.tail
|
||||
}
|
||||
|
||||
func (r *Ring) Push(v interface{}) {
|
||||
if r.IsFull() {
|
||||
r.grow()
|
||||
}
|
||||
|
||||
r.elements[r.tail] = v
|
||||
r.tail = (r.tail + 1) % len(r.elements)
|
||||
}
|
||||
|
||||
func (r *Ring) Pop() (interface{}, bool) {
|
||||
if r.Len() == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
value := r.elements[r.head]
|
||||
r.elements[r.head] = nil // Clear the value to avoid memory leak
|
||||
r.head = (r.head + 1) % len(r.elements)
|
||||
return value, true
|
||||
}
|
||||
|
||||
func (r *Ring) Peek() interface{} {
|
||||
if r.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
return r.elements[r.head]
|
||||
}
|
||||
|
||||
func (r *Ring) Clear() {
|
||||
r.head = 0
|
||||
r.tail = 0
|
||||
r.elements = make([]interface{}, 0, 8)
|
||||
}
|
||||
|
||||
func (r *Ring) IsEmpty() bool {
|
||||
return r.Len() == 0
|
||||
}
|
||||
|
||||
func (r *Ring) Size() int {
|
||||
return len(r.elements)
|
||||
}
|
||||
|
||||
func (r *Ring) IsFull() bool {
|
||||
if (r.tail+1)%len(r.elements) == r.head {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Grow increases the size of the ring buffer if it is full.
|
||||
// It copies the existing elements to a new larger slice.
|
||||
// If the ring is empty, it initializes it with a minimum size.
|
||||
func (r *Ring) grow() {
|
||||
newSize := len(r.elements) * 2
|
||||
if newSize == 0 {
|
||||
newSize = 8 // Minimum size
|
||||
}
|
||||
newElements := make([]interface{}, newSize)
|
||||
|
||||
if r.head < r.tail {
|
||||
// | ... head ..... tail ... |
|
||||
copy(newElements, r.elements[r.head:r.tail])
|
||||
} else {
|
||||
// elements: |... tail head ... |
|
||||
// newElements: | head ..... tail 00000000 |
|
||||
copy(newElements, r.elements[r.head:])
|
||||
copy(newElements[len(r.elements)-r.head:], r.elements[:r.tail])
|
||||
}
|
||||
|
||||
r.elements = newElements
|
||||
r.head = 0
|
||||
r.tail = r.Len()
|
||||
|
||||
fmt.Println("growed to size:", newSize, "head:", r.head, "tail:", r.tail)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package kcp
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRing(t *testing.T) {
|
||||
r := NewRing(1)
|
||||
for i := 0; i < 64; i++ {
|
||||
r.Push(i)
|
||||
if r.Len() != i+1 {
|
||||
t.Errorf("Expected length %d, got %d", i+1, r.Len())
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 32; i++ {
|
||||
val, ok := r.Pop()
|
||||
if !ok || val != i {
|
||||
t.Errorf("Expected to pop %d, got %d (ok: %v)", i, val, ok)
|
||||
}
|
||||
}
|
||||
|
||||
if r.Len() != 32 {
|
||||
t.Errorf("Expected length 32 after popping 32 elements, got %d", r.Len())
|
||||
}
|
||||
|
||||
// Push more elements to test the ring's behavior
|
||||
size := r.Len()
|
||||
for i := 0; i < 32; i++ {
|
||||
r.Push(i)
|
||||
if r.Len() != i+1+size {
|
||||
t.Errorf("Expected length %d, got %d", i+1+size, r.Len())
|
||||
}
|
||||
}
|
||||
|
||||
if r.Len() != 64 {
|
||||
t.Errorf("Expected length 64 after pushing 32 more elements, got %d", r.Len())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user