std1.0.0-beta-7 SafeC docs

Source collections/ringbuffer.h

View in the repository

// SafeC Standard Library — Lock-Free Ring Buffer (real-time audio / DSP safe)
// Single-producer / single-consumer; power-of-two capacity; no dynamic allocation.
// Uses atomic load/store for head and tail to guarantee correct ordering.
// Freestanding-safe.
#pragma once

#define RING_DEFAULT_CAP  4096   // bytes; override before including if needed

namespace std {

struct RingBuffer {
    []unsigned char   buf;    // backing store (set by RingBuffer::over)
    unsigned long     cap;    // capacity in bytes (must be power of two)
    unsigned long     mask;   // cap - 1
    volatile unsigned long head;   // write position (producer)
    volatile unsigned long tail;   // read position (consumer)

    // Initialise over an existing backing store, which must outlive the ring
    // (a static array, typically); its length is rounded down to a power of
    // two for the capacity.
    static struct RingBuffer over([]unsigned char buf);

    // Return number of bytes currently readable.
    unsigned long length() const;

    // Return number of bytes that can be written without blocking.
    unsigned long writable() const;

    // Return 1 if empty.
    int  is_empty() const;

    // Return 1 if full.
    int  is_full() const;

    // Write as much of `data` as fits.  Returns bytes actually written.
    unsigned long write([]const unsigned char data);

    // Read up to out.len bytes into `out`.  Returns bytes actually read.
    unsigned long read([]unsigned char out);

    // Like read, without consuming.  Returns bytes copied.
    unsigned long peek([]unsigned char out) const;

    // One byte at a time (the Fifo protocol, std/collections/traits.h):
    // enqueue returns 1, or 0 if full; dequeue returns null if empty.
    int   enqueue(unsigned char b);
    ?unsigned char dequeue();

    // Discard `len` bytes.  Returns bytes discarded.
    unsigned long discard(unsigned long len);

    // Reset (empty) the buffer.  Safe only when no concurrent access.
    void  clear();
};

// Static-capacity helper: declares a RingBuffer backed by a static array of `N` bytes.
// Usage: RING_STATIC(my_ring, 1024);
#ifdef __SAFEC_COMPAT_PREPROCESSOR__   // function-like macro: compat mode only
#define RING_STATIC(name, N)                          \
    static unsigned char name##_storage_[N];          \
    static struct RingBuffer name = { name##_storage_, N, N-1, 0, 0 }
#endif

} // namespace std