nettools/data_structures/cbuf.go

96 lines
1.8 KiB
Go

package dbUtils
import (
"sync"
)
// Basic Circular buffer interface
type ICBuf[T any] interface {
Push(item T)
Get() []T
}
// Implementation of ICBuf interface
// Simpliest circular buffer implementation
// If thread safety is needed -- use CBufSync
type CBuf[T any] struct {
Buffer []T
Cursor int
Capacity int
}
// Same as pushing back to array
func (cbuf *CBuf[T]) Push(item T) {
cbuf.Buffer[cbuf.Cursor] = item
cbuf.Cursor++
if cbuf.Cursor >= cbuf.Capacity {
cbuf.Cursor = 0
}
println(cbuf.Cursor)
}
// This method isn't a part of ICBuf interface
//
// It pushes item to the "buffer start"
// (Right before the cursor)
// removing item from back
func (cbuf *CBuf[T]) PushFront(item T) {
cbuf.Buffer = append(
append(cbuf.Buffer[cbuf.Cursor+1:], cbuf.Buffer[:cbuf.Cursor]...),
item,
)
cbuf.Cursor = 0
}
// Just returning the whole buffer in the correct order
func (cbuf *CBuf[T]) Get() []T {
return append(cbuf.Buffer[cbuf.Cursor:], cbuf.Buffer[:cbuf.Cursor]...)
}
func NewCBuf[T any](capacity int) *CBuf[T] {
return &CBuf[T]{
Buffer: make([]T, capacity),
Capacity: capacity,
}
}
// Same CBuf, but with mutex
type CBufSync[T any] struct {
Buffer []T
Cursor int
Capacity int
Mu *sync.RWMutex
}
func NewCBufSync[T any](capacity int) *CBufSync[T] {
return &CBufSync[T]{
Mu: &sync.RWMutex{},
}
}
func (cbuf *CBufSync[T]) Push(item T) {
cbuf.Mu.Lock()
cbuf.Buffer[cbuf.Cursor] = item
cbuf.Cursor++
if cbuf.Cursor >= cbuf.Capacity {
cbuf.Cursor = 0
}
cbuf.Mu.Unlock()
}
func (cbuf *CBufSync[T]) PushFront(item T) {
cbuf.Mu.Lock()
cbuf.Buffer = append(
append(cbuf.Buffer[cbuf.Cursor+1:], cbuf.Buffer[:cbuf.Cursor]...),
item,
)
cbuf.Cursor = 0
cbuf.Mu.Unlock()
}
func (cbuf *CBufSync[T]) Get() []T {
cbuf.Mu.RLock()
defer cbuf.Mu.RUnlock()
return append(cbuf.Buffer[cbuf.Cursor:], cbuf.Buffer[:cbuf.Cursor]...)
}