evnty
Version:
Async-first, reactive event handling library for complex event flows in browser and Node.js
172 lines (170 loc) • 4.82 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "RingBuffer", {
enumerable: true,
get: function() {
return RingBuffer;
}
});
const DEFAULT_CAPACITY = 8;
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.cjs.map