This commit is contained in:
xtaci
2025-06-05 17:47:17 +08:00
parent da3a437911
commit c505f434cc
2 changed files with 139 additions and 0 deletions
+102
View File
@@ -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)
}
+37
View File
@@ -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())
}
}