Fast, Zero-Dependency, TypeScript-based data structures for high-performance applications.
npm install fastds[![Github Build Status][github-image]][github-url]
[![NPM version][npm-image]][npm-url]
[![Downloads][downloads-image]][npm-url]
[![Coverage Status][codecov-image]][codecov-url]
[![Snyk][snyk-image]][snyk-url]
Fast, zero-dependency TypeScript data structures optimized for high-performance applications.
- 🚀 High Performance - Up to 37% faster than popular alternatives
- 🔄 O(1) Operations - Constant time push, pop, shift, unshift operations
- 📦 Zero Dependencies - No external runtime dependencies
- 🔍 TypeScript Native - Full type safety and IntelliSense support
- 💾 Memory Efficient - Smart memory management with automatic cleanup
- 🎯 Production Ready - Battle-tested with 100% test coverage
``bash`
npm install fastdsor
yarn add fastdsor
pnpm add fastds
`typescript
import { RingBuffer, BinarySearchArray } from 'fastds';
// Create a high-performance circular buffer
const buffer = new RingBuffer
buffer.push(1).push(2).push(3);
console.log(buffer.shift()); // 1
console.log(buffer.pop()); // 3
// Create a sorted array with binary search
const sorted = new BinarySearchArray
sorted.insert(5);
sorted.insert(2);
sorted.insert(8);
console.log(sorted.indexOf(5)); // 1 (sorted: [2, 5, 8])
`
A high-performance circular buffer (double-ended queue) with O(1) operations for both ends.
#### Why Use RingBuffer?
- Queue/Deque Operations: Perfect for FIFO/LIFO operations, message queues, and task scheduling
- Sliding Windows: Efficient for implementing sliding window algorithms
- Stream Buffers: Ideal for I/O operations, network buffers, and data streaming
- Performance Critical: When you need faster operations than JavaScript's native Array
#### Basic Usage
`typescript
import { RingBuffer } from 'fastds';
// Create with optional initial capacity
const buffer = new RingBuffer
// Add elements
buffer.push('world'); // Add to end
buffer.unshift('hello'); // Add to beginning
// Remove elements
const first = buffer.shift(); // Remove from beginning: 'hello'
const last = buffer.pop(); // Remove from end: 'world'
// Peek without removing
buffer.push('a', 'b', 'c');
console.log(buffer.peekFirst()); // 'a'
console.log(buffer.peekLast()); // 'c'
console.log(buffer.peekAt(1)); // 'b'
`
#### Advanced Operations
`typescript
// Create from array
const numbers = RingBuffer.from([1, 2, 3, 4, 5]);
// Array-like operations
numbers.slice(1, 3); // [2, 3]
numbers.indexOf(3); // 2
numbers.has(4); // true
numbers.toArray(); // [1, 2, 3, 4, 5]
// Modify at index
numbers.setOne(2, 10); // Replace index 2 with 10
numbers.setOne(2, 20, true); // Insert 20 at index 2
// Remove elements
numbers.removeOne(1); // Remove element at index 1
numbers.removeFirst(10); // Remove first occurrence of 10
numbers.remove(0, 2); // Remove 2 elements starting at index 0
// Iteration
for (const value of numbers) {
console.log(value);
}
// Drain iterator (removes elements while iterating)
const drainIter = numbers.drain();
for (const value of drainIter) {
console.log(value); // Buffer becomes empty after iteration
}
`
#### Memory Management
`typescript
const buffer = new RingBuffer
// Add many elements
for (let i = 0; i < 10000; i++) {
buffer.push({ data: i });
}
// Compact: remove gaps and optimize memory
buffer.compact((item) => item.data % 2 === 0); // Keep only even numbers
// Resize: adjust capacity
buffer.resize(500); // Shrink if possible
// Clear: remove all elements and reset
buffer.clear();
`
A sorted array with O(log n) search operations using binary search algorithms.
#### Why Use BinarySearchArray?
- Sorted Collections: Maintains elements in sorted order automatically
- Fast Lookups: O(log n) search performance for large datasets
- Range Queries: Efficiently find elements within a range
- Priority Systems: Implement priority queues and ordered lists
#### Basic Usage
`typescript
import { BinarySearchArray } from 'fastds';
// Create with a comparator function
const numbers = new BinarySearchArray
// Elements are automatically sorted on insertion
numbers.insert(5); // [5]
numbers.insert(2); // [2, 5]
numbers.insert(8); // [2, 5, 8]
numbers.insert(5); // [2, 5, 5, 8] - duplicates allowed
// Binary search operations
console.log(numbers.indexOf(5)); // 1 - first occurrence
console.log(numbers.has(8)); // true
`
#### Advanced Search Operations
`typescript
// Custom object sorting
interface Task {
priority: number;
name: string;
}
const tasks = new BinarySearchArray
(a, b) => a.priority - b.priority
);
tasks.insert({ priority: 3, name: 'Medium task' });
tasks.insert({ priority: 1, name: 'High priority' });
tasks.insert({ priority: 5, name: 'Low priority' });
// Access sorted elements
console.log(tasks.at(0)); // { priority: 1, name: 'High priority' }
// Find insertion points
const newTask = { priority: 2, name: 'New task' };
const lowerBound = tasks.lowerBound(newTask); // First position >= 2
const upperBound = tasks.upperBound(newTask); // First position > 2
// Remove elements
tasks.removeFirst(newTask); // Remove first matching element
tasks.removeOne(0); // Remove at index
tasks.remove(0, 2); // Remove range
// Iteration (in sorted order)
for (const task of tasks) {
console.log(task.name);
}
`
`typescript`
class MessageQueue
private buffer = new RingBuffer
enqueue(message: T): void {
if (this.buffer.length >= this.buffer.capacity) {
this.buffer.shift(); // Remove oldest if full
}
this.buffer.push(message);
}
dequeue(): T | undefined {
return this.buffer.shift();
}
peek(): T | undefined {
return this.buffer.peekFirst();
}
size(): number {
return this.buffer.length;
}
}
`typescript`
class RateLimiter {
private timestamps: RingBuffer
private windowMs: number;
private maxRequests: number;
constructor(maxRequests: number, windowMs: number) {
this.timestamps = new RingBuffer
this.windowMs = windowMs;
this.maxRequests = maxRequests;
}
tryRequest(): boolean {
const now = Date.now();
const cutoff = now - this.windowMs;
// Remove old timestamps outside the window
while (!this.timestamps.isEmpty() &&
this.timestamps.peekFirst()! < cutoff) {
this.timestamps.shift();
}
if (this.timestamps.length < this.maxRequests) {
this.timestamps.push(now);
return true;
}
return false;
}
}
`typescript
interface ScheduledTask {
runAt: number;
task: () => void;
id: string;
}
class TaskScheduler {
private tasks = new BinarySearchArray
(a, b) => a.runAt - b.runAt
);
schedule(task: () => void, delayMs: number): string {
const id = crypto.randomUUID();
this.tasks.insert({
runAt: Date.now() + delayMs,
task,
id
});
return id;
}
getNextTask(): ScheduledTask | undefined {
if (this.tasks.length === 0) return undefined;
const next = this.tasks.at(0);
if (next && next.runAt <= Date.now()) {
this.tasks.removeOne(0);
return next;
}
return undefined;
}
cancel(id: string): boolean {
const index = this.tasks.indexOf({ id } as any);
if (index >= 0) {
this.tasks.removeOne(index);
return true;
}
return false;
}
}
`
FastDS significantly outperforms popular alternatives in various scenarios:
FastDS RingBuffer: 65,390,479 ops/sec
denque: 54,993,484 ops/sec (19% slower)
double-ended-queue: 38,349,016 ops/sec (41% slower)
`$3
`
FastDS RingBuffer: 552,017,913 ops/sec
denque: 416,564,218 ops/sec (25% slower)
`$3
`
FastDS RingBuffer: 1,831 ops/sec
denque: 1,796 ops/sec (2% slower)
double-ended-queue: 387 ops/sec (79% slower)
`API Reference
$3
#### Constructor & Static Methods
-
new RingBuffer - Create a new ring buffer
- RingBuffer.from - Create from an array#### Properties
-
length: number - Number of elements
- capacity: number - Current capacity#### Core Operations
-
push(value: T): this - Add to end
- pop(): T | undefined - Remove from end
- shift(): T | undefined - Remove from beginning
- unshift(value: T): this - Add to beginning#### Access Methods
-
peekAt(index: number): T | undefined - Get element at index
- peekFirst(): T | undefined - Get first element
- peekLast(): T | undefined - Get last element#### Modification Methods
-
setOne(index: number, value: T, insert?: boolean): boolean - Set/insert at index
- removeOne(index: number): number - Remove at index
- removeFirst(value: T, index?: number): number - Remove first occurrence
- clear(): this - Remove all elements#### Utility Methods
-
toArray(): T[] - Convert to array
- slice(start?: number, end?: number): T[] - Get slice as array
- indexOf(value: T, index?: number): number - Find index of value
- has(value: T): boolean - Check if contains value
- compact(filter: (value: T) => boolean): boolean - Filter and compact$3
#### Constructor
-
new BinarySearchArray - Create with comparator#### Properties
-
length: number - Number of elements#### Operations
-
insert(value: T): number - Insert in sorted position
- at(index: number): T | undefined - Get element at index
- indexOf(value: T, index?: number): number - Binary search for value
- has(value: T): boolean - Check if contains value
- lowerBound(value: T): number - Find first position >= value
- upperBound(value: T): number - Find first position > value
- removeOne(index: number): number - Remove at index
- removeFirst(value: T): number - Remove first occurrenceTypeScript Support
FastDS is written in TypeScript and provides full type definitions:
`typescript
import { RingBuffer, BinarySearchArray, type Comparator } from 'fastds';// Full type inference
const buffer = new RingBuffer();
buffer.push(123); // ❌ Type error
// Custom types
interface User {
id: number;
name: string;
score: number;
}
const users = new RingBuffer();
const sortedUsers = new BinarySearchArray(
(a, b) => a.score - b.score
);
``Contributions are welcome! Please feel free to submit a Pull Request.
Copyright (c) 2025 Ivan Zakharchanka
[npm-url]: https://www.npmjs.com/package/fastds
[downloads-image]: https://img.shields.io/npm/dw/fastds.svg?maxAge=43200
[npm-image]: https://img.shields.io/npm/v/fastds.svg?maxAge=43200
[github-url]: https://github.com/3axap4eHko/fastds/actions
[github-image]: https://github.com/3axap4eHko/fastds/actions/workflows/build.yml/badge.svg?branch=master
[codecov-url]: https://codecov.io/gh/3axap4eHko/fastds
[codecov-image]: https://codecov.io/gh/3axap4eHko/fastds/branch/master/graph/badge.svg?maxAge=43200
[snyk-url]: https://snyk.io/test/npm/fastds/latest
[snyk-image]: https://snyk.io/test/github/3axap4eHko/fastds/badge.svg?maxAge=43200