fastds
Version:
Fast, Zero-Dependency, TypeScript-based data structures for high-performance applications.
434 lines (332 loc) • 11.7 kB
Markdown
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 fastds
yarn add fastds
pnpm add fastds
```
```typescript
import { RingBuffer, BinarySearchArray } from 'fastds';
// Create a high-performance circular buffer
const buffer = new RingBuffer<number>();
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<number>((a, b) => a - b);
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<string>(100);
// 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'
```
```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
}
```
```typescript
const buffer = new RingBuffer<object>(1000);
// 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<number>((a, b) => a - b);
// 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
```
```typescript
// Custom object sorting
interface Task {
priority: number;
name: string;
}
const tasks = new BinarySearchArray<Task>(
(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<T> {
private buffer = new RingBuffer<T>(1000);
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<number>;
private windowMs: number;
private maxRequests: number;
constructor(maxRequests: number, windowMs: number) {
this.timestamps = new RingBuffer<number>(maxRequests);
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<ScheduledTask>(
(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)
```
```
FastDS RingBuffer: 552,017,913 ops/sec
denque: 416,564,218 ops/sec (25% slower)
```
```
FastDS RingBuffer: 1,831 ops/sec
denque: 1,796 ops/sec (2% slower)
double-ended-queue: 387 ops/sec (79% slower)
```
- `new RingBuffer<T>(capacity?: number)` - Create a new ring buffer
- `RingBuffer.from<T>(values: T[])` - Create from an array
- `length: number` - Number of elements
- `capacity: number` - Current capacity
- `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
- `peekAt(index: number): T | undefined` - Get element at index
- `peekFirst(): T | undefined` - Get first element
- `peekLast(): T | undefined` - Get last element
- `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
- `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
- `new BinarySearchArray<T>(comparator: (a: T, b: T) => number)` - Create with comparator
- `length: number` - Number of elements
- `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 occurrence
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<string>();
buffer.push(123); // ❌ Type error
// Custom types
interface User {
id: number;
name: string;
score: number;
}
const users = new RingBuffer<User>();
const sortedUsers = new BinarySearchArray<User>(
(a, b) => a.score - b.score
);
```
Contributions are welcome! Please feel free to submit a Pull Request.
[ ](./LICENSE)
Copyright (c) 2025 Ivan Zakharchanka
[ ]: https://www.npmjs.com/package/fastds
[ ]: https://img.shields.io/npm/dw/fastds.svg?maxAge=43200
[ ]: https://img.shields.io/npm/v/fastds.svg?maxAge=43200
[ ]: https://github.com/3axap4eHko/fastds/actions
[ ]: https://github.com/3axap4eHko/fastds/actions/workflows/build.yml/badge.svg?branch=master
[ ]: https://codecov.io/gh/3axap4eHko/fastds
[ ]: https://codecov.io/gh/3axap4eHko/fastds/branch/master/graph/badge.svg?maxAge=43200
[ ]: https://snyk.io/test/npm/fastds/latest
[ ]: https://snyk.io/test/github/3axap4eHko/fastds/badge.svg?maxAge=43200
[![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