eve.util.ringbuffer
A fixed-capacity ring buffer for byte data.
Part of EVE's Buffer Ownership Redesign (BUFFER-OWNERSHIP-REDESIGN.md §4.1). Provides Solution A: a pre-sized ring buffer that eliminates GC allocation on the send hot path when configured via preallocatedSendBuffer.
Designed for send-queue use in Layer 2 transports: pre-allocated once at connection setup, then zero-allocation in steady state. All methods are @nogc @safe nothrow (except initialize() which is @nogc @trusted nothrow).
Memory Management: Backing storage is allocated via malloc() in initialize() and freed via free() in dispose(). This keeps the buffer outside GC-managed memory, eliminating GC scanning overhead for large buffers and ensuring compliance with ADR-003 (no GC allocation in Layer 2).
Important: The developer is responsible for calling dispose() to free memory. There is no destructor — this is intentional to avoid destructor overhead in performance-critical code paths. Failure to call dispose() will leak memory.
Data is stored in a single contiguous ubyte[] slab. The write position (_head) and read position (_tail) wrap around modulo _capacity. _used tracks the number of live bytes so that the full/empty ambiguity is resolved without wasting a slot.
Layout when partially filled (no wrap):
[....TTTTTTTTTHHHH........]
^tail ^headLayout when wrapped:
[HHHH........TTTTTTTTTTTT]
^head ^tailDesign decision: separate _used counter instead of the traditional "waste one slot" approach. This allows capacity() bytes of usable storage rather than capacity - 1, which matters for send queues where the buffer is sized to match highWaterMark.
Copyright
Types 1
Fixed-capacity ring buffer for ubyte data.
Allocation occurs once in initialize() via malloc(). All subsequent operations are @nogc. Call dispose() to release the backing storage via free().
Memory ownership: The developer must call dispose() to free memory. There is no destructor — this design choice avoids destructor overhead for maximum performance. Failure to call dispose() leaks memory.
The struct is non-copyable (@disable this(this)) to prevent accidental duplication of the backing storage pointer. Pass by reference or store as a field in a class.
Buffer Ownership (TERMINOLOGY.md): The backing storage is EVE-Owned after initialize(). append() uses Copy semantics — the caller may reuse or free the source buffer immediately. front() returns a Borrowed slice valid only until the next append() or consume() call.
private ubyte[] _storageprivate size_t _capacityprivate size_t _headprivate size_t _tailprivate size_t _usedvoid initialize(size_t capacity) @trusted nothrow @nogcAllocate backing storage for the ring buffer.const(ubyte)[] front() const @trusted nothrow @nogcGet a contiguous view of the front (readable) portion of the buffer.