Кольцевой буфер

Кольцевой (циклический) буфер — массив фиксированного размера с двумя указателями: head (читаем) и tail (пишем). При достижении конца массива указатель «оборачивается» на начало.

┌───┬───┬───┬───┬───┐
│   │ 2 │ 3 │ 4 │   │
└───┴───┴───┴───┴───┘
  ↑ head           ↑ tail

Даёт O(1) для Enqueue и Dequeue без аллокаций.

type RingBuffer[T any] struct {
    data []T
    head int
    tail int
    size int
    cap  int
}

func NewRingBuffer[T any](cap int) *RingBuffer[T] {
    return &RingBuffer[T]{data: make([]T, cap), cap: cap}
}

func (r *RingBuffer[T]) Enqueue(v T) bool {
    if r.size == r.cap { return false } // переполнен
    r.data[r.tail] = v
    r.tail = (r.tail + 1) % r.cap
    r.size++
    return true
}

func (r *RingBuffer[T]) Dequeue() (T, bool) {
    if r.size == 0 { var z T; return z, false }
    v := r.data[r.head]
    r.head = (r.head + 1) % r.cap
    r.size--
    return v, true
}

func (r *RingBuffer[T]) Len() int  { return r.size }
func (r *RingBuffer[T]) Full() bool { return r.size == r.cap }
import "sync"

type BoundedQueue[T any] struct {
    buf  *RingBuffer[T]
    mu   sync.Mutex
    notEmpty sync.Cond
    notFull  sync.Cond
}

func (q *BoundedQueue[T]) Put(v T) {
    q.mu.Lock()
    for q.buf.Full() { q.notFull.Wait() }
    q.buf.Enqueue(v)
    q.notEmpty.Signal()
    q.mu.Unlock()
}

func (q *BoundedQueue[T]) Take() T {
    q.mu.Lock()
    for q.buf.Len() == 0 { q.notEmpty.Wait() }
    v, _ := q.buf.Dequeue()
    q.notFull.Signal()
    q.mu.Unlock()
    return v
}
  • Буферы аудио/видео потоков.
  • Логгеры с ограниченной историей (последние N событий).
  • Межпотоковая передача данных без аллокаций.
  • Сетевые пакетные буферы.

ЗаданиеСложность
1Упражнение 1easy
2Упражнение 2easy
3Упражнение 3medium