パッケージの詳細

ringbud

vqueiroz951.0.22

A lightweight, high-performance Ring Buffer for streaming data using JavaScript TypedArrays.

ring-buffer, ring, ring-buffer, worklet

readme

RingBud

A lightweight, high-performance Ring Buffer for streaming data using JavaScript TypedArrays.

Features

  • 🧠 Frame-based buffering (configurable frame size)
  • Zero dependencies
  • 🧵 Supports all major TypedArrays (e.g. Float32Array, Uint8Array, etc.)
  • 📦 Memory efficient with optional frame trimming
  • 🔁 Sync & async iteration support
  • Fully tested and predictable behavior
  • 🧰 Customizable preallocation and cache options

Installation

npm install ringbud

Quick Start

import { RingBufferU8 } from "ringbud";

// Create a ring buffer with frame size of 100
const rb = new RingBufferU8(100);

// Write 50 bytes (not enough for a full frame)
rb.write(new Uint8Array(50).fill(1));
console.log(rb.empty()); // true

// Write 50 more bytes (now we have a complete frame)
rb.write(new Uint8Array(50).fill(1));
console.log(rb.empty()); // false

// Read one frame of 100 bytes
const frame = rb.read();
console.log(frame); // Uint8Array(100)

// After reading, it becomes empty again
console.log(rb.empty()); // true

Supported Types

You can instantiate ring buffers for:

  • Uint8ArrayRingBufferU8
  • Uint16ArrayRingBufferU16
  • Float32ArrayRingBufferF32

Each subclass wraps the base RingBufferBase with preconfigured types.


Configuration Options

All constructors accept:

{
  frameSize: number,                // Number of elements per frame (required)
  preallocateFrameCount?: number,  // Default: 10
  frameCacheSize?: number          // Default: 0 (no trim)
}

Frame Cache Size (Clamping)

When frameCacheSize > 0, the ring buffer trims memory usage by shifting unread bytes after every .read(). This reduces buffer growth at the cost of additional memory copying.


API Reference

Constructor

new RingBufferU8(frameSize: number, options?: {
  preallocateFrameCount?: number;
  frameCacheSize?: number;
});

Methods

Method Description
write(data) Appends a TypedArray to the buffer
read() Returns the next full frame, or null
drain() Returns remaining incomplete data
peek() Returns the entire buffer content (not a copy)
empty() true if no full frame is available
remainingFrames() Number of full frames available to read
rewind() Resets read offset so frames can be re-read
Symbol.iterator() Enables for (const frame of buffer)
Symbol.asyncIterator() Enables for await (const frame of buffer)

Example: Iteration

for (const frame of rb) {
  console.log(frame); // each is a complete frame
}

// or async
for await (const frame of rb) {
  await process(frame);
}

Example: Auto-Trimming

const rb = new RingBufferU8(100, { frameCacheSize: 1 });

rb.write(new Uint8Array(300)); // 3 frames
rb.read();                     // returns 1st frame

// Buffer automatically shifts remaining frames to the front
rb.peek().subarray(0, 200);    // contains frame 2 and 3

Validations & Safety

  • frameSize must be an integer ≥ 1
  • preallocateFrameCount must be ≥ 1 (if set)
  • Partial frames are never returned from .read() or iterators
  • Trimming only occurs after reads when frameCacheSize > 0
  • If iteration is used, all frames are consumed as if .read() was called repeatedly
  • Frames can be shared or copied depending on cache config

TypedArray Support

Internally, the base class accepts any TypedArray constructor:

new RingBufferBase({
  frameSize: 256,
  TypedArrayConstructor: Uint16Array
});

Built-in classes like RingBufferF32 are wrappers over this API.


Examples

Draining Partial Data

const rb = new RingBufferU8(100);

rb.write(new Uint8Array(230));
rb.read();           // reads 1 frame (100 bytes)
rb.read();           // reads 1 more frame (100 bytes)
rb.read();           // null (30 bytes left)

rb.drain();          // returns 30 bytes

Rewind

rb.rewind();         // enables re-reading all written frames
for (const frame of rb) {
  console.log(frame);
}