Create a circular queue of the size of the argument, uCapacity
.
const cb = new circular_buffer(3);
cb.capacity; // 3
Queues may be, but do not have to be, typed. If they are, all methods will also be appropriately typed, both in arguments and return values.
const cb = new circular_buffer<string>(2);
The current size cap, as a cache. Use .capacity instead.
The current cursor in the underlying array. You should never need this; it is an internal implementation detail. This describes the start position in the storage of the storage mapping.
The current used range within the dataset array. Values outside this range aren't trustworthy. Use .length instead.
The current offset in the underlying array. You should never need this; it is an internal implementation detail. This is an eviction count from the datastructure, giving you total queue depth.
The actual dataset. Not in order as the outside world would expect. If you want this functionality, use .toArray() instead.
The number of spaces available to be filled (ie, .capacity - .length
.)
const cb = new circular_buffer(3);
cb.available; // 3
cb.push(1); // ok, returns 1
cb.available; // 2
cb.pop(); // ok, returns 1, container now empty
cb.available; // 3
cb.fill(3); // [3,3,3]
cb.available; // 0
cb.clear(); // [ , , ]
cb.available; // 3
The number of spaces offered, total, regardless of what's currently used.
const cb = new circular_buffer(3);
cb.capacity; // 3
cb.push(1); // ok, returns 1
cb.capacity; // 3
cb.pop(); // ok, returns 1, container now empty
cb.capacity; // 3
Setting .capacity
resizes the container (and clips contents if
necessary.) Calling this is equivalent to calling [[circular_buffer_js.resize]].
const cb = new circular_buffer(3);
cb.capacity; // 3 - [ , , ]
cb.push(1); // ok, returns 1
cb.capacity; // 3 - [1, , ]
cb.resize(4); // ok
cb.capacity; // 4 - [1, , , ]
Gets the first element of the queue; throws RangeError if the queue is empty.
const cb = new circular_buffer(3);
cb.push(1); // ok, returns 1
cb.push(2); // ok, returns 2
cb.push(3); // ok, returns 3
cb.first; // 1
cb.clear(); // ok, container now empty
cb.first; // throws RangeError, because the container is empty
true
when the container has no contents (ie, .length === 0
); false
otherwise.
const cb = new circular_buffer(3);
cb.isEmpty; // true
cb.push(1); // ok, returns 1
cb.isEmpty; // false
cb.clear(); // ok, container now empty
cb.isEmpty; // true
true
when the container has no space left (ie, .length === .capacity
);
false
otherwise.
const cb = new circular_buffer(3);
cb.isFull; // false
cb.push(1); // ok, returns 1
cb.push(2); // ok, returns 2
cb.push(3); // ok, returns 3
cb.isFull; // true
cb.clear(); // ok, container now empty
cb.isFull; // false
Gets the last element of the queue; throws RangeError if the queue is empty.
const cb = new circular_buffer(3);
cb.push(1); // ok, returns 1
cb.push(2); // ok, returns 2
cb.push(3); // ok, returns 3
cb.last; // 3
cb.clear(); // ok, container now empty
cb.last; // throws RangeError, because the container is empty
The number of spaces currently filled.
const cb = new circular_buffer(3);
cb.length; // 0
cb.push(1); // ok, returns 1
cb.length; // 1
cb.pop(); // ok, returns 1, container now empty
cb.length; // 0
cb.fill(3); // [3,3,3]
cb.length; // 3
cb.clear(); // [ , , ]
cb.length; // 0
Sets the length of the data inside the queue, but does not change the size of the queue itself (if you'd like this, set [[circular_buffer_js.capacity]] or call [[circular_buffer_js.resize]] instead, as you prefer.)
As an odd result, setting .length
to a length longer than or equal to
the .length
of the data, but smaller than the .capacity
of the
container, is a no-op.
Attempting to set a .length
longer than the .capacity
of the container
will throw.
const cb = circular_buffer.from([1,2,3]);
cb.length; // 3
cb.toArray(); // [1,2,3]
cb.length = 2; // ok, truncates the `3` at end
cb.length; // 2
cb.toArray(); // [1,2, ]
cb.length = 3; // ok, no change
cb.length; // 2
cb.toArray(); // [1,2, ]
cb.length = 1; // ok, truncates the `2` at end
cb.toArray(); // [1, , ]
cp.capacity = 1; // ok, resizes the container
cb.toArray(); // [1]
cb.length = 2; // throws, container too small
cb.length = -2; // throws, no negative lengths
cb.length = 1.2; // throws, no fractional lengths
Returns the value at a given index, or throws RangeError if that value does not exist (container too small or nonsensical index.)
const cb = new circular_buffer(3);
cb.push(1); // ok, returns 1
cb.push(2); // ok, returns 2
cb.push(3); // ok, returns 3
cb.at(0); // ok, returns 1
cb.at(2); // ok, returns 3
cb.at(4); // throws RangeError, larger than the container
cb.at(-1); // throws RangeError, nonsense index
cb.at(0.5); // throws RangeError, nonsense index
cb.at("Z"); // throws RangeError, nonsense index
Empties a container. Returns the previous contents.
const cb = new circular_buffer(3);
cb.push(10); // ok, returns 10
cb.push(20); // ok, returns 20
cb.push(30); // ok, returns 30
cb.last; // 30
cb.length; // 3
cb.clear(); // ok, returns [10,20,30]; container now empty
cb.last; // throws RangeError, because the container is empty
cb.length; // 0
Iterates a container with a predicate, testing for all truthy.
const cb = circular_buffer.from([1,2,'three']);
cb.every( i => typeof i === 'number' ); // false
Fills a container with a repeated value.
const cb = new circular_buffer(3);
cb.length; // 0
cb.at(2); // throws RangeError
cb.fill('Bob'); // ['Bob', 'Bob', 'Bob']
cb.length; // 3
cb.at(2); // 'Bob'
Using an identifier predicate, return either the first matching
element or undefined
.
const dogs = ['beagle', 'doberman', 'deputy'];
is_dog = animal => dogs.includes(animal);
const room = ['siamese', 'beagle', 'cockatoo'];
console.log(room.find(is_dog)); // prints 'beagle'
Returns the index of the first element matching the search element provided, or -1 in the case of no matching elements.
const numbers = circular_buffer.from(['One', 'Two', 'Three']);
console.log(`Index of Two: ${numbers.indexOf('Two')}`); // expects 1
console.log(`Index of Four: ${numbers.indexOf('Four')}`); // expects -1
You may also pass a starting point, if you want to.
const letters = circular_buffer.from(['a','b','a','b']);
console.log(`Index of b starting from 2: ${numbers.indexOf('b', 2)}`); // expects 3
Fetches the current offset (or eviction count) of the container. This allows a developer to know how deep into an infinite queue they are, and how far back their rollback window reaches if any.
const cb = new circular_buffer(3);
cb.toArray(); // []
cb.push(10); // ok, returns 1
cb.push(20); // ok, returns 2
cb.push(30); // ok, returns 3
cb.toArray(); // [10,20,30]
cb.offset(); // 0
cb.pop(); // 10
cb.offset(); // 1
cb.pop(); // 20
cb.offset(); // 2
cb.pop(); // 30
cb.offset(); // 3
cb.pop(); // throws - queue is now empty
Pops a value from the front of the container, by returning it and removing
it from the container; throws RangeError
if the container is already
empty.
const cb = new circular_buffer(3);
cb.push(1); // ok, returns 1
cb.push(2); // ok, returns 2
cb.pop(); // ok, returns 1
cb.pop(); // ok, returns 2
cb.pop(); // throws RangeError, container has nothing to pop out
Returns the value at a given run position, or throws RangeError if that value does not exist (container too small, too large, or nonsensical index.)
The difference between pos/1
and at/1
is that at/1
gives you
elements against the current head cursor, whereas pos/1
gives you
elements against the original queue head. So, most people will want
at/1
, since it gives you contents according to what's currently in
the container. But if you're trying to get fixed positions in the
long term stream, and know that they're in the current window, like
you would have with a lockstep networking library, pos/1
is what
you're looking for.
const cb = new circular_buffer(3);
cb.push(10); // ok, returns 10
cb.push(20); // ok, returns 20
cb.push(30); // ok, returns 30
cb.at(0); // ok, returns 10
cb.pos(0); // ok, returns 10
cb.at(1); // ok, returns 20
cb.pos(1); // ok, returns 20
cb.at(2); // ok, returns 30
cb.pos(2); // ok, returns 30
cb.pos(4); // throws RangeError, larger than the container
cb.offset(); // 0
cb.pop(); // 10. container is now [20, 30, _]
cb.offset(); // 1
cb.at(0); // ok, returns 20
cb.pos(0); // throws, as container is past this location
cb.at(1); // ok, returns 30 - at(1) is head+1
cb.pos(1); // ok, returns 20 - pos(1) is original position 1, which is currently head
cb.at(2); // throws, past fill
cb.pos(2); // ok, returns 30
cb.pop(); // 10. container is now [20, 30, _]
cb.at(0); // ok, returns 30
cb.pos(0); // throws, as container is past this location
cb.at(1); // throws, past fill
cb.pos(1); // throws, as container is past this location
cb.at(2); // throws, past fill
cb.pos(2); // ok, returns 30
cb.at(-1); // throws RangeError, nonsense index
cb.at(0.5); // throws RangeError, nonsense index
cb.at("Z"); // throws RangeError, nonsense index
Pushes a value onto the end of the container; throws RangeError
if the
container is already full.
const cb = new circular_buffer(3);
cb.push(1); // ok, returns 1
cb.push(2); // ok, returns 2
cb.push(3); // ok, returns 3
cb.push(4); // throws RangeError, container only has 3 spots
Changes the capacity of the queue. If the new capacity of the queue is
too small for the prior contents, they are trimmed. The second argument,
preferEnd
, an optional boolean that defaults false, will cause removals
to be taken from the front instead of the back.
const cb = new circular_buffer(3);
cb.toArray(); // []
cb.push(1); // ok, returns 1
cb.push(2); // ok, returns 2
cb.push(3); // ok, returns 3
cb.toArray(); // [1,2,3]
cb.resize(5); // ok
cb.toArray(); // [1,2,3, , ]
cb.resize(2); // ok
cb.toArray(); // [1,2]
cb.resize(4); // ok
cb.toArray(); // [1,2, , ]
cb.resize(0); // ok
cb.toArray(); // []
cb.resize(4); // ok
cb.toArray(); // [ , , , ]
cb.push(1); // ok, returns 1
cb.push(2); // ok, returns 2
cb.push(3); // ok, returns 3
cb.push(4); // ok, returns 4
cb.toArray(); // [1,2,3,4]
cb.resize(2); // ok
cb.toArray(); // [3,4]
Reverses a container.
const cb = circular_buffer.from([3,2,1]);
cb.reverse();
cb.pop(); // ok, returns 1
cb.pop(); // ok, returns 2
cb.pop(); // ok, returns 3
Pushes a value onto the end of the container; removes front to make space
if necessary. Throws RangeError
if the container is zero-size.
Returns the value shoved out, if any.
const cb = new circular_buffer(3);
cb.shove(1); // ok, returns undefined
cb.shove(2); // ok, returns undefined
cb.shove(3); // ok, returns undefined
cb.toArray(); // [1,2,3]
cb.push(4); // ok, returns 1
cb.toArray(); // [2,3,4]
Iterates a container with a predicate, testing for at least one truthy.
const cb = circular_buffer.from([1,2,'three']);
cb.some( i => typeof i === 'string' ); // true
Returns the complete, ordered contents of the queue, as an array.
const cb = new circular_buffer(3);
cb.toArray(); // []
cb.push(1); // ok, returns 1
cb.push(2); // ok, returns 2
cb.push(3); // ok, returns 3
cb.toArray(); // [1,2,3]
cb.pop(); // ok, returns 1
cb.toArray(); // [2,3]
Creates a circular buffer from an ArrayLike
or an Iterable
, with a
matching capacity. Static method, and as such should not be called from
an instance (so, do not call using new
.)
const cb = circular_buffer.from([1,2,3]);
cb.pop(); // ok, returns 1
cb.pop(); // ok, returns 2
cb.pop(); // ok, returns 3
cb.pop(); // throws RangeError, empty
Generated using TypeDoc
This is a circular queue.