Skip to content

Commit

Permalink
Merge pull request #1 from snickbit/main
Browse files Browse the repository at this point in the history
docs: add jsdocs and type definitions
  • Loading branch information
kleinron authored May 7, 2022
2 parents bc50ee0 + c33087a commit 9610e68
Show file tree
Hide file tree
Showing 22 changed files with 1,321 additions and 184 deletions.
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
{
"name": "lite-fifo",
"version": "0.2.2",
"version": "0.3.0",
"license": "MIT",
"main": "src/index.js",
"types": "types/index.d.ts",
"homepage": "https://github.com/kleinron/lite-fifo.git#readme",
"description": "Lightweight, optimized, and efficient implementations for FIFO (queue) data structure",
"devDependencies": {
"mocha": "^9.2.2",
"seedrandom": "^3.0.5",
"semistandard": "^16.0.1",
"shelljs": "^0.8.5",
"semistandard": "^16.0.1"
"typescript": "^4.6.4"
},
"scripts": {
"lint": "semistandard",
"lint-with-fix": "semistandard --fix",
"test": "mocha test/ --recursive --check-leaks --require test/src/setup.js",
"benchmark": "node ./benchmark/report-generator.js",
"benchmark-dynamic-array": "node ./benchmark/report-generator.js ./benchmark/report-config-dynamic-array.json"
"benchmark-dynamic-array": "node ./benchmark/report-generator.js ./benchmark/report-config-dynamic-array.json",
"types": "node ./node_modules/typescript/bin/tsc"
},
"author": {
"name": "Ron Klein",
Expand Down
89 changes: 89 additions & 0 deletions src/ChunkedQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ const { LinkedQueue } = require('./LinkedQueue');
const { CyclicQueue } = require('./CyclicQueue');
const { bindMethods } = require('./util');

/**
* @type ChunkedQueue
*/
class ChunkedQueue {
/**
* @param {number} [chunkSize]
* @returns {ChunkedQueue}
*/
constructor (chunkSize) {
if (chunkSize === undefined) {
chunkSize = 1024;
Expand All @@ -19,11 +26,20 @@ class ChunkedQueue {
bindMethods.call(this);
}

/**
* Clear the queue.
* @returns {void}
*/
// noinspection JSUnusedGlobalSymbols
clear () {
this._queue.clear();
}

/**
* Add an item to the queue.
* @param {any} item
* @returns {void}
*/
enqueue (item) {
if (this._queue.size() === 0) {
this._queue.enqueue(new CyclicQueue(this._chunkSize));
Expand All @@ -36,6 +52,10 @@ class ChunkedQueue {
lastChunk.enqueue(item);
}

/**
* Return the first inserted (or the "oldest") item in the queue, and removes it from the queue.
* @returns {any}
*/
dequeue () {
const firstChunk = this._queue.peekFirst();
const result = firstChunk.dequeue();
Expand All @@ -45,6 +65,10 @@ class ChunkedQueue {
return result;
}

/**
* Return the current size of the queue.
* @returns {number}
*/
size () {
const size = this._queue.size();
switch (size) {
Expand All @@ -61,20 +85,49 @@ class ChunkedQueue {
return newestSize + oldestSize + innerSize;
}

/**
* Return the last inserted (or the "newest") item in the queue, without removing it from the queue.
* @returns {any}
* @throws {Error} if the queue is empty
*/
peekLast () {
if (this.size() === 0) {
throw new Error('cannot peek from an empty queue');
}
return this._queue.peekLast().peekLast();
}

/**
* Return the first inserted (or the "oldest") item in the queue, without removing it from the queue.
* @returns {any}
* @throws {Error} if the queue is empty
*/
peekFirst () {
if (this.size() === 0) {
throw new Error('cannot peek from an empty queue');
}
return this._queue.peekFirst().peekFirst();
}

/**
* Iterate over the items in the queue without changing the queue.
* Iteration order is the insertion order: first inserted item would be returned first.
* In essence this supports JS iterations of the pattern `for (let x of queue) { ... }.`
*
* @example
* const queue = new DynamicArrayQueue();
* queue.enqueue(123);
* queue.enqueue(45);
* for (let item of queue) {
* console.log(item);
* }
* // ==> output would be:
* // 123
* // 45
* // and the queue would remain unchanged
*
* @returns {Generator<any, void, ?>}
*/
[Symbol.iterator] () {
const queue = this._queue;
function * generator () {
Expand All @@ -88,6 +141,26 @@ class ChunkedQueue {
return generator();
}

/**
* Iterate over the items in the queue.
* Every iterated item is removed from the queue.
* Iteration order is the insertion order: first inserted item would be returned first.
*
* @example
* const queue = new DynamicArrayQueue();
* queue.enqueue(123);
* queue.enqueue(45);
* for (let item of queue.drainingIterator()) {
* console.log(item);
* }
* console.log(`size = ${queue.size()}`);
* // ==> output would be:
* // 123
* // 45
* // size = 0
*
* @returns {Generator<any, void, ?>}
*/
drainingIterator () {
const queue = this._queue;
function * generator () {
Expand All @@ -101,6 +174,13 @@ class ChunkedQueue {
return generator();
}

/**
* Copy the items of the queue to the given array arr, starting from index startIndex.
* First item in the array is first item inserted to the queue, and so forth.
* @param {any[]} arr
* @param {number} [startIndex=0]
* @returns {void}
*/
copyTo (arr, startIndex) {
if (startIndex === undefined) {
startIndex = 0;
Expand All @@ -112,12 +192,21 @@ class ChunkedQueue {
}
}

/**
* Create an array with the same size as the queue, populate it with the items in the queue, keeping the iteration order, and return it.
* @returns {any[]}
*/
toArray () {
const arr = new Array(this.size());
this.copyTo(arr, 0);
return arr;
}

/**
* Return a JSON representation (as a string) of the queue.
* The queue is represented as an array: first item in the array is the first one inserted to the queue and so forth.
* @returns {string}
*/
toJSON () {
return JSON.stringify(this.toArray());
}
Expand Down
97 changes: 97 additions & 0 deletions src/CyclicQueue.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
const { bindMethods } = require('./util');

/**
* @type CyclicQueue
*/
class CyclicQueue {
/**
* @param {number} [capacity]
* @returns {CyclicQueue}
*/
constructor (capacity) {
if (capacity === undefined) {
capacity = 16;
Expand All @@ -16,21 +23,38 @@ class CyclicQueue {
this.clear();
}

/**
* Clear the queue.
* @returns {void}
*/
clear () {
this._arr = new Array(this._capacity);
this._size = 0;
this._lastIndex = 0;
this._firstIndex = 0;
}

/**
* @returns {number}
*/
capacity () {
return this._arr.length;
}

/**
* Return the current size of the queue.
* @returns {number}
*/
size () {
return this._size;
}

/**
* Add an item to the queue.
* @param {any} item
* @returns {void}
* @throws {Error} Might throw an exception if the capacity is exceeded.
*/
enqueue (item) {
if (this._size === this._arr.length) {
throw new Error('queue overflow');
Expand All @@ -43,10 +67,18 @@ class CyclicQueue {
this._size++;
}

/**
* @returns {number}
*/
_increaseMod (val) {
return val + 1 === this._arr.length ? 0 : val + 1;
}

/**
* Return the first inserted (or the "oldest") item in the queue, and removes it from the queue.
* @returns {any}
* @throws {Error} Might throw an exception if the queue is empty.
*/
dequeue () {
if (this._size === 0) {
throw new Error('queue underflow');
Expand All @@ -58,20 +90,49 @@ class CyclicQueue {
return result;
}

/**
* Return the last inserted (or the "newest") item in the queue, without removing it from the queue.
* @returns {any}
* @throws {Error} if the queue is empty
*/
peekLast () {
if (this._size === 0) {
throw new Error('cannot peek from an empty queue');
}
return this._arr[this._lastIndex];
}

/**
* Return the first inserted (or the "oldest") item in the queue, without removing it from the queue.
* @returns {any}
* @throws {Error} if the queue is empty
*/
peekFirst () {
if (this._size === 0) {
throw new Error('cannot peek from an empty queue');
}
return this._arr[this._firstIndex];
}

/**
* Iterate over the items in the queue without changing the queue.
* Iteration order is the insertion order: first inserted item would be returned first.
* In essence this supports JS iterations of the pattern `for (let x of queue) { ... }.`
*
* @example
* const queue = new DynamicArrayQueue();
* queue.enqueue(123);
* queue.enqueue(45);
* for (let item of queue) {
* console.log(item);
* }
* // ==> output would be:
* // 123
* // 45
* // and the queue would remain unchanged
*
* @returns {{[Symbol.iterator]: (function(): {next: function(): ({done: boolean, value?: any})})}}
*/
[Symbol.iterator] () {
let firstIndex = this._firstIndex;
const incMod = this._increaseMod.bind(this);
Expand All @@ -92,6 +153,26 @@ class CyclicQueue {
};
}

/**
* Iterate over the items in the queue.
* Every iterated item is removed from the queue.
* Iteration order is the insertion order: first inserted item would be returned first.
*
* @example
* const queue = new DynamicArrayQueue();
* queue.enqueue(123);
* queue.enqueue(45);
* for (let item of queue.drainingIterator()) {
* console.log(item);
* }
* console.log(`size = ${queue.size()}`);
* // ==> output would be:
* // 123
* // 45
* // size = 0
*
* @returns {{[Symbol.iterator]: (function(): {next: function(): ({done: boolean, value?: any})})}}
*/
drainingIterator () {
const me = this;

Expand All @@ -110,6 +191,13 @@ class CyclicQueue {
};
}

/**
* Copy the items of the queue to the given array arr, starting from index startIndex.
* First item in the array is first item inserted to the queue, and so forth.
* @param {any[]} arr
* @param {number} [startIndex=0]
* @returns {void}
*/
copyTo (arr, startIndex) {
if (startIndex === undefined) {
startIndex = 0;
Expand All @@ -121,12 +209,21 @@ class CyclicQueue {
}
}

/**
* Create an array with the same size as the queue, populate it with the items in the queue, keeping the iteration order, and return it.
* @returns {any[]}
*/
toArray () {
const arr = new Array(this.size());
this.copyTo(arr, 0);
return arr;
}

/**
* Return a JSON representation (as a string) of the queue.
* The queue is represented as an array: first item in the array is the first one inserted to the queue and so forth.
* @returns {string}
*/
toJSON () {
return JSON.stringify(this.toArray());
}
Expand Down
Loading

0 comments on commit 9610e68

Please sign in to comment.