UNPKG

evnty

Version:

Async-first, reactive event handling library for complex event flows in browser and Node.js

162 lines (160 loc) 4.61 kB
const DEFAULT_CAPACITY = 8; export class RingBuffer { #buffer; #head = 0; #tail = 0; #mask; #length = 0; #shiftCount = 0; [Symbol.toStringTag] = 'RingBuffer'; static from(values) { const n = values.length; const ring = new RingBuffer(n + 1); for(let i = 0; i < n; i++){ ring.#buffer[i] = values[i]; } ring.#head = 0; ring.#tail = n; ring.#length = n; return ring; } constructor(capacity = DEFAULT_CAPACITY){ const size = Math.max(1 << 32 - Math.clz32(capacity - 1), DEFAULT_CAPACITY); this.#buffer = new Array(size); this.#mask = size - 1; } get length() { return this.#length; } get left() { return this.#shiftCount; } get right() { return this.#shiftCount + this.#length; } isWrapped() { return this.#head > this.#tail; } isEmpty() { return this.#tail === this.#head; } grow(capacity = this.#mask + 1) { const buffer = this.#buffer; const bufferLength = buffer.length; if (bufferLength >= capacity + 1) { return; } const size = 1 << 32 - Math.clz32(capacity); this.#buffer.length = size; const oldTail = this.#tail; if (oldTail < this.#head) { for(let i = 0; i < oldTail; i++){ buffer[bufferLength + i] = buffer[i]; buffer[i] = undefined; } this.#tail = bufferLength + oldTail; } this.#mask = size - 1; } push(value) { const nextTail = this.#tail + 1 & this.#mask; if (nextTail === this.#head) { this.grow(this.#mask + 2); this.#buffer[this.#tail] = value; this.#tail = this.#tail + 1 & this.#mask; } else { this.#buffer[this.#tail] = value; this.#tail = nextTail; } this.#length++; return this; } unshift(value) { const newHead = this.#head - 1 & this.#mask; if (newHead === this.#tail) { this.grow(this.#mask + 2); this.#head = this.#head - 1 & this.#mask; } else { this.#head = newHead; } this.#buffer[this.#head] = value; this.#length++; return this; } peek(index) { if (index < 0 || index >= this.#length) { return undefined; } return this.#buffer[this.#head + index & this.#mask]; } peekAt(logicalIndex) { return this.peek(logicalIndex - this.#shiftCount); } shift() { if (this.#head === this.#tail) { return undefined; } const value = this.#buffer[this.#head]; this.#buffer[this.#head] = undefined; this.#head = this.#head + 1 & this.#mask; this.#length--; this.#shiftCount++; return value; } shiftN(n) { const count = Math.min(n, this.#length); for(let i = 0; i < count; i++){ this.#buffer[this.#head] = undefined; this.#head = this.#head + 1 & this.#mask; } this.#length -= count; this.#shiftCount += count; return count; } pop() { if (this.#head === this.#tail) { return undefined; } this.#tail = this.#tail - 1 & this.#mask; const value = this.#buffer[this.#tail]; this.#buffer[this.#tail] = undefined; this.#length--; return value; } clear(preserveCapacity = false) { const capacity = preserveCapacity ? this.#buffer.length : DEFAULT_CAPACITY; this.#buffer.length = 0; this.#buffer.length = capacity; this.#head = 0; this.#tail = 0; this.#length = 0; this.#shiftCount = 0; this.#mask = capacity - 1; return this; } [Symbol.iterator]() { const buffer = this.#buffer; const mask = this.#mask; const length = this.#length; let count = 0; let idx = this.#head; return { next: ()=>{ if (count >= length) { return { done: true, value: undefined }; } const value = buffer[idx]; idx = idx + 1 & mask; count++; return { done: false, value }; } }; } } //# sourceMappingURL=ring-buffer.js.map