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]...) }