Documentation
¶
Overview ¶
Package carousel provides generic fixed-capacity ring data structures.
Two types are available:
RingBuffer — a fixed-capacity FIFO circular buffer. Not safe for concurrent use; callers must synchronize externally.
RingQueue — a concurrent blocking FIFO queue backed by RingBuffer. Supports both drop-on-full and evict-oldest-on-full enqueue strategies, and a blocking RingQueue.Pop that integrates with context.Context.
Index ¶
- Variables
- type RingBuffer
- func (rb *RingBuffer[T]) Cap() int
- func (rb *RingBuffer[T]) Clear()
- func (rb *RingBuffer[T]) Drain() []T
- func (rb *RingBuffer[T]) ForcePush(item T) (evicted bool)
- func (rb *RingBuffer[T]) Len() int
- func (rb *RingBuffer[T]) Peek() (T, bool)
- func (rb *RingBuffer[T]) Pop() (T, bool)
- func (rb *RingBuffer[T]) Push(item T) bool
- func (rb *RingBuffer[T]) Snapshot() []T
- type RingQueue
- func (q *RingQueue[T]) Cap() int
- func (q *RingQueue[T]) Close()
- func (q *RingQueue[T]) Drain() []T
- func (q *RingQueue[T]) Enqueue(item T) error
- func (q *RingQueue[T]) ForceEnqueue(item T) (evicted bool, err error)
- func (q *RingQueue[T]) Len() int
- func (q *RingQueue[T]) Pop(ctx context.Context) (T, error)
- func (q *RingQueue[T]) Snapshot() []T
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrClosed = errors.New("carousel: queue is closed")
ErrClosed is returned by RingQueue.Enqueue, RingQueue.ForceEnqueue, and RingQueue.Pop after RingQueue.Close has been called.
var ErrFull = errors.New("carousel: queue is full")
ErrFull is returned by RingQueue.Enqueue when the queue is at capacity.
Functions ¶
This section is empty.
Types ¶
type RingBuffer ¶
type RingBuffer[T any] struct { // contains filtered or unexported fields }
RingBuffer is a fixed-capacity FIFO circular buffer.
The zero value is not usable; create instances with NewRingBuffer. Not safe for concurrent use — callers are responsible for synchronization when shared across goroutines.
Internal layout: head is the index of the oldest element; the write position (tail) is derived as (head+size)%len(data) and is not stored.
Example ¶
package main
import (
"fmt"
"github.com/maxence2997/carousel"
)
func main() {
buf := carousel.NewRingBuffer[int](3)
buf.Push(1)
buf.Push(2)
buf.Push(3)
buf.ForcePush(4)
value, _ := buf.Pop()
fmt.Println(value)
fmt.Println(buf.Drain())
}
Output: 2 [3 4]
func NewRingBuffer ¶
func NewRingBuffer[T any](capacity int) *RingBuffer[T]
NewRingBuffer creates a RingBuffer with the given capacity.
Panics if capacity < 1.
func (*RingBuffer[T]) Cap ¶
func (rb *RingBuffer[T]) Cap() int
Cap returns the maximum number of items the buffer can hold.
func (*RingBuffer[T]) Clear ¶
func (rb *RingBuffer[T]) Clear()
Clear removes all items and releases slot references for GC. No-op when the buffer is already empty.
func (*RingBuffer[T]) Drain ¶
func (rb *RingBuffer[T]) Drain() []T
Drain removes and returns all items in FIFO order. Returns nil if the buffer is empty. After Drain, the buffer is empty and all internal slots are zeroed.
func (*RingBuffer[T]) ForcePush ¶
func (rb *RingBuffer[T]) ForcePush(item T) (evicted bool)
ForcePush appends item to the back of the buffer. If the buffer is full, the oldest item is evicted to make room. Returns true if an item was evicted.
func (*RingBuffer[T]) Len ¶
func (rb *RingBuffer[T]) Len() int
Len returns the number of items currently in the buffer.
func (*RingBuffer[T]) Peek ¶
func (rb *RingBuffer[T]) Peek() (T, bool)
Peek returns the oldest item without removing it. Returns the zero value of T and false if the buffer is empty.
func (*RingBuffer[T]) Pop ¶
func (rb *RingBuffer[T]) Pop() (T, bool)
Pop removes and returns the oldest item. Returns the zero value of T and false if the buffer is empty.
func (*RingBuffer[T]) Push ¶
func (rb *RingBuffer[T]) Push(item T) bool
Push appends item to the back of the buffer. Returns false if the buffer is full; the item is not added.
func (*RingBuffer[T]) Snapshot ¶ added in v1.1.0
func (rb *RingBuffer[T]) Snapshot() []T
Snapshot returns a copy of all items in FIFO order (oldest first). Returns nil if the buffer is empty.
The returned slice is independent of the buffer; mutations to either do not affect the other. Non-destructive: buffer state is unchanged.
Independence is shallow: if T is a pointer type or contains pointers, the pointed-to values are shared between the snapshot and the buffer.
type RingQueue ¶
type RingQueue[T any] struct { // contains filtered or unexported fields }
RingQueue is a concurrent fixed-capacity FIFO queue backed by RingBuffer.
The zero value is not usable; create instances with NewRingQueue. Multiple goroutines may call Enqueue and ForceEnqueue concurrently. Pop is intended to be called by a single goroutine (consumer). Close is idempotent and must be called when the queue is no longer needed.
Example ¶
package main
import (
"context"
"fmt"
"github.com/maxence2997/carousel"
)
func main() {
q := carousel.NewRingQueue[string](3)
defer q.Close()
_ = q.Enqueue("alpha")
_ = q.Enqueue("beta")
item, _ := q.Pop(context.Background())
fmt.Println(item)
fmt.Println(q.Drain())
}
Output: alpha [beta]
func NewRingQueue ¶
NewRingQueue creates a RingQueue with the given capacity.
Panics if capacity < 1.
func (*RingQueue[T]) Cap ¶
Cap returns the fixed capacity of the queue. Capacity is set at construction and never changes; RingQueue does not support resizing.
func (*RingQueue[T]) Close ¶
func (q *RingQueue[T]) Close()
Close marks the queue as closed and wakes any goroutine blocked in Pop. Idempotent — safe to call more than once; subsequent calls are no-ops.
func (*RingQueue[T]) Drain ¶
func (q *RingQueue[T]) Drain() []T
Drain removes and returns all current items in FIFO order without blocking. Returns nil if the queue is empty.
Unlike RingQueue.Pop, Drain does not wait for new items — it returns whatever is in the buffer at the moment of the call. Useful for bulk reads or flushing remaining items during shutdown without going through the blocking Pop interface.
func (*RingQueue[T]) Enqueue ¶
Enqueue adds item to the queue. Returns ErrFull if the queue is at capacity. Returns ErrClosed if the queue has been closed.
func (*RingQueue[T]) ForceEnqueue ¶
ForceEnqueue adds item to the queue, evicting the oldest item if full. Returns true if an item was evicted. Returns ErrClosed if the queue has been closed.
func (*RingQueue[T]) Pop ¶
Pop blocks until an item is available, the context is canceled, or the queue is closed. Available items are always delivered before cancellation or close signals are returned. Returns ErrClosed when the queue is closed and all remaining items have been consumed. Returns ctx.Err() when the context is canceled and the buffer is empty.
Concurrent calls to Pop are not supported — use a single consumer goroutine. ctx must be non-nil; pass context.Background to opt out of cancellation.
func (*RingQueue[T]) Snapshot ¶ added in v1.1.0
func (q *RingQueue[T]) Snapshot() []T
Snapshot returns a copy of all current items in FIFO order without removing them. Returns nil if the queue is empty.
Acquires the queue lock for the duration of the in-package copy; no user-supplied code runs under the lock. Non-destructive: queue state is unchanged after the call.
Lock hold time is O(N) where N = RingQueue.Len at the moment of the call. For very large capacities under contention, prefer a steady-state design that does not call Snapshot from a hot path.